Annotation of Net2/kern/kern_execve.c, revision 1.1.1.2

1.1       root        1: /*
1.1.1.2 ! root        2:  * Copyright (c) 1989, 1990, 1991, 1992 William F. Jolitz, TeleMuse
        !             3:  * All rights reserved.
1.1       root        4:  *
1.1.1.2 ! root        5:  * Redistribution and use in source and binary forms, with or without
        !             6:  * modification, are permitted provided that the following conditions
        !             7:  * are met:
        !             8:  * 1. Redistributions of source code must retain the above copyright
        !             9:  *    notice, this list of conditions and the following disclaimer.
        !            10:  * 2. Redistributions in binary form must reproduce the above copyright
        !            11:  *    notice, this list of conditions and the following disclaimer in the
        !            12:  *    documentation and/or other materials provided with the distribution.
        !            13:  * 3. All advertising materials mentioning features or use of this software
        !            14:  *    must display the following acknowledgement:
        !            15:  *     This software is a component of "386BSD" developed by 
        !            16:  *     William F. Jolitz, TeleMuse.
        !            17:  * 4. Neither the name of the developer nor the name "386BSD"
        !            18:  *    may be used to endorse or promote products derived from this software
        !            19:  *    without specific prior written permission.
        !            20:  *
        !            21:  * THIS SOFTWARE IS A COMPONENT OF 386BSD DEVELOPED BY WILLIAM F. JOLITZ 
        !            22:  * AND IS INTENDED FOR RESEARCH AND EDUCATIONAL PURPOSES ONLY. THIS 
        !            23:  * SOFTWARE SHOULD NOT BE CONSIDERED TO BE A COMMERCIAL PRODUCT. 
        !            24:  * THE DEVELOPER URGES THAT USERS WHO REQUIRE A COMMERCIAL PRODUCT 
        !            25:  * NOT MAKE USE OF THIS WORK.
        !            26:  *
        !            27:  * FOR USERS WHO WISH TO UNDERSTAND THE 386BSD SYSTEM DEVELOPED
        !            28:  * BY WILLIAM F. JOLITZ, WE RECOMMEND THE USER STUDY WRITTEN 
        !            29:  * REFERENCES SUCH AS THE  "PORTING UNIX TO THE 386" SERIES 
        !            30:  * (BEGINNING JANUARY 1991 "DR. DOBBS JOURNAL", USA AND BEGINNING 
        !            31:  * JUNE 1991 "UNIX MAGAZIN", GERMANY) BY WILLIAM F. JOLITZ AND 
        !            32:  * LYNNE GREER JOLITZ, AS WELL AS OTHER BOOKS ON UNIX AND THE 
        !            33:  * ON-LINE 386BSD USER MANUAL BEFORE USE. A BOOK DISCUSSING THE INTERNALS 
        !            34:  * OF 386BSD ENTITLED "386BSD FROM THE INSIDE OUT" WILL BE AVAILABLE LATE 1992.
        !            35:  *
        !            36:  * THIS SOFTWARE IS PROVIDED BY THE DEVELOPER ``AS IS'' AND
        !            37:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            38:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            39:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE DEVELOPER BE LIABLE
        !            40:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            41:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            42:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            43:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            44:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            45:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            46:  * SUCH DAMAGE.
1.1       root       47:  *
                     48:  * This procedure implements a minimal program execution facility for
                     49:  * 386BSD. It interfaces to the BSD kernel as the execve system call.
                     50:  * Significant limitations and lack of compatiblity with POSIX are
                     51:  * present with this version, to make its basic operation more clear.
                     52:  *
                     53:  */
                     54: 
                     55: #include "param.h"
                     56: #include "systm.h"
1.1.1.2 ! root       57: #include "signalvar.h"
        !            58: #include "resourcevar.h"
1.1       root       59: #include "proc.h"
                     60: #include "mount.h"
                     61: #include "namei.h"
                     62: #include "vnode.h"
                     63: #include "file.h"
                     64: #include "exec.h"
                     65: #include "stat.h"
                     66: #include "wait.h"
                     67: #include "mman.h"
1.1.1.2 ! root       68: #include "malloc.h"
1.1       root       69: 
                     70: #include "vm/vm.h"
                     71: #include "vm/vm_param.h"
                     72: #include "vm/vm_map.h"
                     73: #include "vm/vm_kern.h"
                     74: 
                     75: #include "machine/reg.h"
                     76: 
1.1.1.2 ! root       77: extern int dostacklimits;
        !            78: #define        copyinoutstr    copyinstr
1.1       root       79: 
                     80: /*
1.1.1.2 ! root       81:  * execve() system call.
1.1       root       82:  */
                     83: 
                     84: /* ARGSUSED */
                     85: execve(p, uap, retval)
                     86:        struct proc *p;
                     87:        register struct args {
                     88:                char    *fname;
                     89:                char    **argp;
                     90:                char    **envp;
                     91:        } *uap;
                     92:        int *retval;
                     93: {
                     94:        register struct nameidata *ndp;
                     95:        struct nameidata nd;
                     96:        struct exec hdr;
1.1.1.2 ! root       97:        char **argbuf, **argbufp, *stringbuf, *stringbufp;
        !            98:        char **vectp, *ep;
        !            99:        int needsenv, limitonargs, stringlen, addr, size, len,
        !           100:                rv, amt, argc, tsize, dsize, bsize, cnt, foff;
        !           101:        struct vattr attr;
1.1       root      102:        struct vmspace *vs;
1.1.1.2 ! root      103:        caddr_t newframe;
1.1       root      104: 
                    105:        /*
                    106:         * Step 1. Lookup filename to see if we have something to execute.
                    107:         */
                    108:        ndp = &nd;
1.1.1.2 ! root      109:        ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW | SAVENAME;
1.1       root      110:        ndp->ni_segflg = UIO_USERSPACE;
                    111:        ndp->ni_dirp = uap->fname;
                    112: 
                    113:        /* is it there? */
                    114:        if (rv = namei(ndp, p))
                    115:                return (rv);
                    116: 
1.1.1.2 ! root      117:        /* does it have any attributes? */
        !           118:        rv = VOP_GETATTR(ndp->ni_vp, &attr, p->p_ucred, p);
1.1       root      119:        if (rv)
                    120:                goto exec_fail;
1.1.1.2 ! root      121: 
        !           122:        /* is it executable, and a regular file? */
        !           123:        if ((attr.va_mode & VEXEC) == 0 || attr.va_type != VREG) {
        !           124:                rv = EACCES;
1.1       root      125:                goto exec_fail;
1.1.1.2 ! root      126:        }
1.1       root      127: 
                    128:        /*
                    129:         * Step 2. Does the file contain a format we can
                    130:         * understand and execute
                    131:         */
                    132:        rv = vn_rdwr(UIO_READ, ndp->ni_vp, (caddr_t)&hdr, sizeof(hdr),
                    133:                0, UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &amt, p);
                    134: 
                    135:        /* big enough to hold a header? */
                    136:        if (rv)
                    137:                goto exec_fail;
                    138:        
1.1.1.2 ! root      139:        /* ... that we recognize? */
1.1       root      140:        rv = ENOEXEC;
                    141:        if (hdr.a_magic != ZMAGIC)
                    142:                goto exec_fail;
                    143: 
                    144:        /* sanity check  "ain't not such thing as a sanity clause" -groucho */
1.1.1.2 ! root      145:        rv = ENOMEM;
1.1       root      146:        if (/*hdr.a_text == 0 || */ hdr.a_text > MAXTSIZ
1.1.1.2 ! root      147:                || hdr.a_text % NBPG || hdr.a_text > attr.va_size)
1.1       root      148:                goto exec_fail;
                    149: 
                    150:        if (hdr.a_data == 0 || hdr.a_data > DFLDSIZ
1.1.1.2 ! root      151:                || hdr.a_data > attr.va_size
        !           152:                || hdr.a_data + hdr.a_text > attr.va_size)
1.1       root      153:                goto exec_fail;
                    154: 
                    155:        if (hdr.a_bss > MAXDSIZ)
                    156:                goto exec_fail;
                    157:        
                    158:        if (hdr.a_text + hdr.a_data + hdr.a_bss > MAXTSIZ + MAXDSIZ)
                    159:                goto exec_fail;
1.1.1.2 ! root      160: 
        !           161:        if (hdr.a_data + hdr.a_bss > p->p_rlimit[RLIMIT_DATA].rlim_cur)
        !           162:                goto exec_fail;
        !           163: 
        !           164:        if (hdr.a_entry > hdr.a_text + hdr.a_data)
        !           165:                goto exec_fail;
1.1       root      166:        
                    167:        /*
                    168:         * Step 3.  File and header are valid. Now, dig out the strings
                    169:         * out of the old process image.
                    170:         */
                    171: 
1.1.1.2 ! root      172:        /*
        !           173:         * We implement a single-pass algorithm that builds a new stack
        !           174:         * frame within the address space of the "old" process image,
        !           175:         * avoiding the second pass entirely. Thus, the new frame is
        !           176:         * in position to be run. This consumes much virtual address space,
        !           177:         * and two pages more of 'real' memory, such are the costs.
        !           178:         * [Also, note the cache wipe that's avoided!]
1.1       root      179:         */
                    180: 
1.1.1.2 ! root      181:        /* create anonymous memory region for new stack */
        !           182:        vs = p->p_vmspace;
        !           183:        if ((unsigned)vs->vm_maxsaddr + MAXSSIZ < USRSTACK)
        !           184:                newframe = (caddr_t) USRSTACK - MAXSSIZ;
        !           185:        else
        !           186:                vs->vm_maxsaddr = newframe = (caddr_t) USRSTACK - 2*MAXSSIZ;
        !           187: 
        !           188:        /* don't do stack limit checking on traps temporarily XXX*/
        !           189:        dostacklimits = 0;
        !           190: 
        !           191:        rv = vm_allocate(&vs->vm_map, &newframe, MAXSSIZ, FALSE);
        !           192:        if (rv) goto exec_fail;
        !           193: 
1.1       root      194:        /* allocate string buffer and arg buffer */
1.1.1.2 ! root      195:        argbuf = (char **) (newframe + MAXSSIZ - 3*ARG_MAX);
        !           196:        stringbuf = stringbufp = ((char *)argbuf) + 2*ARG_MAX;
        !           197:        argbufp = argbuf;
1.1       root      198: 
                    199:        /* first, do args */
                    200:        vectp = uap->argp;
1.1.1.2 ! root      201:        needsenv = 1;
        !           202:        limitonargs = ARG_MAX;
        !           203:        cnt = 0;
1.1       root      204: 
                    205: do_env_as_well:
                    206:        if(vectp == 0) goto dont_bother;
1.1.1.2 ! root      207: 
        !           208:        /* for each envp, copy in string */
1.1       root      209:        do {
                    210:                /* did we outgrow initial argbuf, if so, die */
1.1.1.2 ! root      211:                if (argbufp == (char **)stringbuf) {
        !           212:                        rv = E2BIG;
        !           213:                        goto exec_dealloc;
        !           214:                }
1.1       root      215:        
                    216:                /* get an string pointer */
                    217:                ep = (char *)fuword(vectp++);
                    218:                if (ep == (char *)-1) {
                    219:                        rv = EFAULT;
1.1.1.2 ! root      220:                        goto exec_dealloc;
1.1       root      221:                }
                    222: 
1.1.1.2 ! root      223:                /* if not a null pointer, copy string */
1.1       root      224:                if (ep) {
1.1.1.2 ! root      225:                        if (rv = copyinoutstr(ep, stringbufp,
        !           226:                                (u_int)limitonargs, (u_int *) &stringlen)) {
        !           227:                                if (rv == ENAMETOOLONG)
        !           228:                                        rv = E2BIG;
        !           229:                                goto exec_dealloc;
        !           230:                        }
        !           231:                        suword(argbufp++, (int)stringbufp);
1.1       root      232:                        cnt++;
1.1.1.2 ! root      233:                        stringbufp += stringlen;
        !           234:                        limitonargs -= stringlen;
1.1       root      235:                } else {
1.1.1.2 ! root      236:                        suword(argbufp++, 0);
1.1       root      237:                        break;
                    238:                }
                    239:        } while (limitonargs > 0);
                    240: 
                    241: dont_bother:
                    242:        if (limitonargs <= 0) {
                    243:                rv = E2BIG;
1.1.1.2 ! root      244:                goto exec_dealloc;
1.1       root      245:        }
                    246: 
1.1.1.2 ! root      247:        /* have we done the environment yet ? */
1.1       root      248:        if (needsenv) {
1.1.1.2 ! root      249:                /* remember the arg count for later */
1.1       root      250:                argc = cnt;
                    251:                vectp = uap->envp;
                    252:                needsenv = 0;
                    253:                goto do_env_as_well;
                    254:        }
                    255:  
1.1.1.2 ! root      256:        /* At this point, one could optionally implement a
        !           257:         * second pass to condense the strings, arguement vectors,
        !           258:         * and stack to fit the fewest pages.
        !           259:         *
        !           260:         * One might selectively do this when copying was cheaper
        !           261:         * than leaving allocated two more pages per process.
        !           262:         */
        !           263: 
        !           264:        /* stuff arg count on top of "new" stack */
        !           265:        argbuf[-1] = (char *)argc;
1.1       root      266: 
                    267:        /*
                    268:         * Step 4. Build the new processes image.
1.1.1.2 ! root      269:         *
        !           270:         * At this point, we are committed -- destroy old executable!
1.1       root      271:         */
                    272: 
1.1.1.2 ! root      273:        /* blow away all address space, except the stack */
        !           274:        rv = vm_deallocate(&vs->vm_map, 0, USRSTACK - 2*MAXSSIZ);
1.1       root      275:        if (rv)
                    276:                goto exec_abort;
                    277: 
1.1.1.2 ! root      278:        /* destroy "old" stack */
        !           279:        if ((unsigned)newframe < USRSTACK - MAXSSIZ) {
        !           280:                rv = vm_deallocate(&vs->vm_map, USRSTACK - MAXSSIZ, MAXSSIZ);
        !           281:                if (rv)
        !           282:                        goto exec_abort;
        !           283:        } else {
        !           284:                rv = vm_deallocate(&vs->vm_map, USRSTACK - 2*MAXSSIZ, MAXSSIZ);
        !           285:                if (rv)
        !           286:                        goto exec_abort;
        !           287:        }
        !           288: 
1.1       root      289:        /* build a new address space */
                    290:        addr = 0;
1.1.1.2 ! root      291: 
        !           292:        /* screwball mode -- special case of 413 to save space for floppy */
1.1       root      293:        if (hdr.a_text == 0) {
                    294:                foff = tsize = 0;
                    295:                hdr.a_data += hdr.a_text;
                    296:        } else {
                    297:                tsize = roundup(hdr.a_text, NBPG);
                    298:                foff = NBPG;
                    299:        }
1.1.1.2 ! root      300: 
        !           301:        /* treat text and data in terms of integral page size */
1.1       root      302:        dsize = roundup(hdr.a_data, NBPG);
                    303:        bsize = roundup(hdr.a_bss + dsize, NBPG);
                    304:        bsize -= dsize;
                    305: 
1.1.1.2 ! root      306:        /* map text & data in file, as being "paged in" on demand */
1.1       root      307:        rv = vm_mmap(&vs->vm_map, &addr, tsize+dsize, VM_PROT_ALL,
1.1.1.2 ! root      308:                MAP_FILE|MAP_COPY|MAP_FIXED, (caddr_t)ndp->ni_vp, foff);
1.1       root      309:        if (rv)
                    310:                goto exec_abort;
                    311: 
1.1.1.2 ! root      312:        /* mark pages r/w data, r/o text */
1.1       root      313:        if (tsize) {
                    314:                addr = 0;
1.1.1.2 ! root      315:                rv = vm_protect(&vs->vm_map, addr, tsize, FALSE,
        !           316:                        VM_PROT_READ|VM_PROT_EXECUTE);
1.1       root      317:                if (rv)
                    318:                        goto exec_abort;
                    319:        }
                    320: 
                    321:        /* create anonymous memory region for bss */
                    322:        addr = dsize + tsize;
                    323:        rv = vm_allocate(&vs->vm_map, &addr, bsize, FALSE);
                    324:        if (rv)
                    325:                goto exec_abort;
                    326: 
                    327:        /*
                    328:         * Step 5. Prepare process for execution.
                    329:         */
                    330: 
1.1.1.2 ! root      331:        /* touchup process information -- vm system is unfinished! */
1.1       root      332:        vs->vm_tsize = tsize/NBPG;              /* text size (pages) XXX */
                    333:        vs->vm_dsize = (dsize+bsize)/NBPG;      /* data size (pages) XXX */
1.1.1.2 ! root      334:        vs->vm_taddr = 0;               /* user virtual address of text XXX */
1.1       root      335:        vs->vm_daddr = (caddr_t)tsize;  /* user virtual address of data XXX */
1.1.1.2 ! root      336:        vs->vm_maxsaddr = newframe;     /* user VA at max stack growth XXX */
        !           337:        vs->vm_ssize =  ((unsigned)vs->vm_maxsaddr + MAXSSIZ
        !           338:                - (unsigned)argbuf)/ NBPG + 1; /* stack size (pages) */
        !           339:        dostacklimits = 1;      /* allow stack limits to be enforced XXX */
1.1       root      340: 
                    341:        /* close files on exec, fixup signals */
                    342:        fdcloseexec(p);
                    343:        execsigs(p);
                    344: 
1.1.1.2 ! root      345:        /* name this process - nameiexec(p, ndp) */
        !           346:        len = MIN(ndp->ni_namelen,MAXCOMLEN);
        !           347:        bcopy(ndp->ni_ptr, p->p_comm, len);
        !           348:        p->p_comm[len] = 0;
        !           349:        
        !           350:        /* mark as executable, wakeup any process that was vforked and tell
        !           351:         * it that it now has it's own resources back */
        !           352:        p->p_flag |= SEXEC;
        !           353:        if (p->p_pptr && (p->p_flag & SPPWAIT)) {
        !           354:            p->p_flag &= ~SPPWAIT;
        !           355:            wakeup(p->p_pptr);
        !           356:        }
        !           357:        
        !           358:        /* implement set userid/groupid */
        !           359:        if ((attr.va_mode&VSUID) && (p->p_flag & STRC) == 0) {
        !           360:            p->p_ucred = crcopy(p->p_ucred);
        !           361:            p->p_cred->p_svuid = p->p_ucred->cr_uid = attr.va_uid;
        !           362:        }
        !           363:        if ((attr.va_mode&VSGID) && (p->p_flag & STRC) == 0) {
        !           364:            p->p_ucred = crcopy(p->p_ucred);
        !           365:            p->p_cred->p_svgid = p->p_ucred->cr_groups[0] = attr.va_gid;
        !           366:        }
        !           367: 
        !           368:        /* setup initial register state */
        !           369:        p->p_regs[SP] = (unsigned) (argbuf - 1);
1.1       root      370:        setregs(p, hdr.a_entry);
1.1.1.2 ! root      371: 
1.1       root      372:        vput(ndp->ni_vp);
1.1.1.2 ! root      373:        FREE(ndp->ni_pnbuf, M_NAMEI);
        !           374: 
        !           375:        /* if tracing process, pass control back to debugger so breakpoints
        !           376:           can be set before the program "runs" */
        !           377:        if (p->p_flag & STRC)
        !           378:                psignal(p, SIGTRAP);
        !           379: 
1.1       root      380:        return (0);
                    381: 
1.1.1.2 ! root      382: exec_dealloc:
        !           383:        /* remove interim "new" stack frame we were building */
        !           384:        vm_deallocate(&vs->vm_map, newframe, MAXSSIZ);
        !           385: 
1.1       root      386: exec_fail:
1.1.1.2 ! root      387:        dostacklimits = 1;
1.1       root      388:        vput(ndp->ni_vp);
1.1.1.2 ! root      389:        FREE(ndp->ni_pnbuf, M_NAMEI);
        !           390: 
1.1       root      391:        return(rv);
                    392: 
                    393: exec_abort:
1.1.1.2 ! root      394:        /* sorry, no more process anymore. exit gracefully */
        !           395:        vm_deallocate(&vs->vm_map, newframe, MAXSSIZ);
1.1       root      396:        vput(ndp->ni_vp);
1.1.1.2 ! root      397:        FREE(ndp->ni_pnbuf, M_NAMEI);
1.1       root      398:        exit(p, W_EXITCODE(0, SIGABRT));
                    399: 
1.1.1.2 ! root      400:        /* NOTREACHED */
        !           401:        return(0);
1.1       root      402: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.