Annotation of Net2/kern/kern_execve, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (c) 1992 William Jolitz. All rights reserved.
        !             3:  * Written by William Jolitz 1/92
        !             4:  *
        !             5:  * Redistribution and use in source and binary forms are freely permitted
        !             6:  * provided that the above copyright notice and attribution and date of work
        !             7:  * and this paragraph are duplicated in all such forms.
        !             8:  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
        !             9:  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
        !            10:  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
        !            11:  *
        !            12:  * This procedure implements a minimal program execution facility for
        !            13:  * 386BSD. It interfaces to the BSD kernel as the execve system call.
        !            14:  * Significant limitations and lack of compatiblity with POSIX are
        !            15:  * present with this version, to make its basic operation more clear.
        !            16:  *
        !            17:  */
        !            18: 
        !            19: #include "param.h"
        !            20: #include "systm.h"
        !            21: #include "proc.h"
        !            22: #include "mount.h"
        !            23: #include "namei.h"
        !            24: #include "vnode.h"
        !            25: #include "file.h"
        !            26: #include "exec.h"
        !            27: #include "stat.h"
        !            28: #include "wait.h"
        !            29: #include "signalvar.h"
        !            30: #include "mman.h"
        !            31: 
        !            32: #include "vm/vm.h"
        !            33: #include "vm/vm_param.h"
        !            34: #include "vm/vm_map.h"
        !            35: #include "vm/vm_kern.h"
        !            36: 
        !            37: #include "machine/reg.h"
        !            38: 
        !            39: static char rcsid[] = "$Header: /usr/bill/working/sys/kern/RCS/kern_execve.c,v 1.3 92/01/21 21:29:13 william Exp $";
        !            40: 
        !            41: /*
        !            42:  * Bill's first-cut execve() system call. Puts hair on your chest.
        !            43:  */
        !            44: 
        !            45: /* ARGSUSED */
        !            46: execve(p, uap, retval)
        !            47:        struct proc *p;
        !            48:        register struct args {
        !            49:                char    *fname;
        !            50:                char    **argp;
        !            51:                char    **envp;
        !            52:        } *uap;
        !            53:        int *retval;
        !            54: {
        !            55:        register struct nameidata *ndp;
        !            56:        int rv, amt;
        !            57:        struct nameidata nd;
        !            58:        struct exec hdr;
        !            59:        char **kargbuf, **kargbufp, *kstringbuf, *kstringbufp;
        !            60:        char **org, **vectp, *ep;
        !            61:        u_int   needsenv, limitonargs, stringlen;
        !            62:        int addr, size;
        !            63:        int argc;
        !            64:        char *cp;
        !            65:        struct stat statb;
        !            66:        struct vmspace *vs;
        !            67:        int tsize, dsize, bsize, cnt, foff;
        !            68: 
        !            69:        /*
        !            70:         * Step 1. Lookup filename to see if we have something to execute.
        !            71:         */
        !            72:        ndp = &nd;
        !            73:        ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW;
        !            74:        ndp->ni_segflg = UIO_USERSPACE;
        !            75:        ndp->ni_dirp = uap->fname;
        !            76: 
        !            77:        /* is it there? */
        !            78:        if (rv = namei(ndp, p))
        !            79:                return (rv);
        !            80: 
        !            81:        /* is it a regular file? */
        !            82:        if (ndp->ni_vp->v_type != VREG) {
        !            83:                vput(ndp->ni_vp);
        !            84:                return(ENOEXEC);
        !            85:        }
        !            86: 
        !            87:        /* is it executable? */
        !            88:        rv = VOP_ACCESS(ndp->ni_vp, VEXEC, p->p_ucred, p);
        !            89:        if (rv)
        !            90:                goto exec_fail;
        !            91:        
        !            92:        rv = vn_stat(ndp->ni_vp, &statb, p);
        !            93:        if (rv)
        !            94:                goto exec_fail;
        !            95: 
        !            96:        /*
        !            97:         * Step 2. Does the file contain a format we can
        !            98:         * understand and execute
        !            99:         */
        !           100:        rv = vn_rdwr(UIO_READ, ndp->ni_vp, (caddr_t)&hdr, sizeof(hdr),
        !           101:                0, UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &amt, p);
        !           102: 
        !           103:        /* big enough to hold a header? */
        !           104:        if (rv)
        !           105:                goto exec_fail;
        !           106:        
        !           107:        /* that we recognize? */
        !           108:        rv = ENOEXEC;
        !           109:        if (hdr.a_magic != ZMAGIC)
        !           110:                goto exec_fail;
        !           111: 
        !           112:        /* sanity check  "ain't not such thing as a sanity clause" -groucho */
        !           113:        if (/*hdr.a_text == 0 || */ hdr.a_text > MAXTSIZ
        !           114:                || hdr.a_text % NBPG || hdr.a_text > statb.st_size)
        !           115:                goto exec_fail;
        !           116: 
        !           117:        if (hdr.a_data == 0 || hdr.a_data > DFLDSIZ
        !           118:                || hdr.a_data > statb.st_size
        !           119:                || hdr.a_data + hdr.a_text > statb.st_size)
        !           120:                goto exec_fail;
        !           121: 
        !           122:        if (hdr.a_bss > MAXDSIZ)
        !           123:                goto exec_fail;
        !           124:        
        !           125:        if (hdr.a_text + hdr.a_data + hdr.a_bss > MAXTSIZ + MAXDSIZ)
        !           126:                goto exec_fail;
        !           127:        
        !           128:        /*
        !           129:         * Step 3.  File and header are valid. Now, dig out the strings
        !           130:         * out of the old process image.
        !           131:         */
        !           132: 
        !           133:        /* assumption: most execve's have less than 256 arguments, with a
        !           134:         * total of string storage space not exceeding 2K. It is more
        !           135:         * frequent that when this fails, string space falls short first
        !           136:         * (e.g. as when a large termcap environment variable is present).
        !           137:         * It is infrequent when more than 256 arguments are used that take
        !           138:         * up less than 2K of space (e.g. args average more than 8 chars).
        !           139:         *
        !           140:         * What we give up in this implementation is a dense encoding of
        !           141:         * the data structure in the receiving program's address space.
        !           142:         * This means that there is plenty of wasted space (up to 6KB)
        !           143:         * as the price we pay for a fast, single pass algorithm.
        !           144:         *
        !           145:         * Our alternative would be to accumulate strings and pointers
        !           146:         * in the first pass, then, knowing the sizes and number of the
        !           147:         * strings, pack them neatly and tightly togeither in the second
        !           148:         * pass. This means two copies of the strings, and string copying
        !           149:         * is much of the cost of exec.
        !           150:         */
        !           151: 
        !           152:        /* allocate string buffer and arg buffer */
        !           153:        org = kargbuf = (char **) kmem_alloc_wait(exec_map,
        !           154:                (NCARGS + PAGE_SIZE)/PAGE_SIZE);
        !           155:        kstringbuf = kstringbufp = ((char *)kargbuf) + NBPG/2;
        !           156:        kargbuf += NBPG/(4*sizeof(int));
        !           157:        kargbufp = kargbuf;
        !           158: 
        !           159:        /* first, do args */
        !           160:        needsenv = 1;
        !           161:        vectp = uap->argp;
        !           162: 
        !           163: do_env_as_well:
        !           164:        cnt = 0;
        !           165:        /* for each envp, copy in string */
        !           166:        limitonargs = NCARGS;
        !           167:        if(vectp == 0) goto dont_bother;
        !           168:        do {
        !           169:                /* did we outgrow initial argbuf, if so, die */
        !           170:                if (kargbufp == (char **)kstringbuf)
        !           171:                        goto exec_fail;
        !           172:        
        !           173:                /* get an string pointer */
        !           174:                ep = (char *)fuword(vectp++);
        !           175:                if (ep == (char *)-1) {
        !           176:                        rv = EFAULT;
        !           177:                        goto exec_fail;
        !           178:                }
        !           179: 
        !           180:                /* if not null pointer, copy in string */
        !           181:                if (ep) {
        !           182:                        if (rv = copyinstr(ep, kstringbufp, limitonargs,
        !           183:                                &stringlen)) goto exec_fail;
        !           184:                        /* assume that strings usually all fit in last page */
        !           185:                        *kargbufp = (char *)(kstringbufp - kstringbuf
        !           186:                                + USRSTACK - NBPG + NBPG/2);
        !           187:                        kargbufp++;
        !           188:                        cnt++;
        !           189:                        kstringbufp += stringlen;
        !           190:                        limitonargs -= stringlen + sizeof(long);
        !           191:                } else {
        !           192:                        *kargbufp++ = 0;
        !           193:                        limitonargs -= sizeof(long);
        !           194:                        break;
        !           195:                }
        !           196:        } while (limitonargs > 0);
        !           197: 
        !           198: dont_bother:
        !           199:        if (limitonargs <= 0) {
        !           200:                rv = E2BIG;
        !           201:                goto exec_fail;
        !           202:        }
        !           203: 
        !           204:        if (needsenv) {
        !           205:                argc = cnt;
        !           206:                vectp = uap->envp;
        !           207:                needsenv = 0;
        !           208:                goto do_env_as_well;
        !           209:        }
        !           210:  
        !           211:        kargbuf[-1] = (char *)argc;
        !           212: 
        !           213:        /*
        !           214:         * Step 4. Build the new processes image.
        !           215:         */
        !           216: 
        !           217:        /* At this point, we are committed -- destroy old executable */
        !           218:        vs = p->p_vmspace;
        !           219:        addr = 0;
        !           220:        size = USRSTACK - addr;
        !           221:        /* blow away all address space */
        !           222:        rv = vm_deallocate(&vs->vm_map, addr, size, FALSE);
        !           223:        if (rv)
        !           224:                goto exec_abort;
        !           225: 
        !           226:        /* build a new address space */
        !           227:        addr = 0;
        !           228:        if (hdr.a_text == 0) {
        !           229:                /* screwball mode */
        !           230:                foff = tsize = 0;
        !           231:                hdr.a_data += hdr.a_text;
        !           232:        } else {
        !           233:                tsize = roundup(hdr.a_text, NBPG);
        !           234:                foff = NBPG;
        !           235:        }
        !           236:        dsize = roundup(hdr.a_data, NBPG);
        !           237:        bsize = roundup(hdr.a_bss + dsize, NBPG);
        !           238:        bsize -= dsize;
        !           239: 
        !           240:        /* map text & data*/
        !           241:        rv = vm_mmap(&vs->vm_map, &addr, tsize+dsize, VM_PROT_ALL,
        !           242:        MAP_FILE|MAP_COPY|MAP_FIXED, (caddr_t)ndp->ni_vp, foff);
        !           243:        if (rv)
        !           244:                goto exec_abort;
        !           245: 
        !           246:        /* r/w data, ro text */
        !           247:        if (tsize) {
        !           248:                addr = 0;
        !           249:                rv = vm_protect(&vs->vm_map, addr, tsize, FALSE, VM_PROT_READ|VM_PROT_EXECUTE);
        !           250:                if (rv)
        !           251:                        goto exec_abort;
        !           252:        }
        !           253: 
        !           254:        /* create anonymous memory region for bss */
        !           255:        addr = dsize + tsize;
        !           256:        rv = vm_allocate(&vs->vm_map, &addr, bsize, FALSE);
        !           257:        if (rv)
        !           258:                goto exec_abort;
        !           259: 
        !           260:        /* create anonymous memory region for stack */
        !           261:        addr = USRSTACK - MAXSSIZ;
        !           262:        rv = vm_allocate(&vs->vm_map, &addr, MAXSSIZ, FALSE);
        !           263:        if (rv)
        !           264:                goto exec_abort;
        !           265: 
        !           266:        /*
        !           267:         * Step 5. Prepare process for execution.
        !           268:         */
        !           269: 
        !           270:        /* touchup process information */
        !           271:        vs->vm_tsize = tsize/NBPG;              /* text size (pages) XXX */
        !           272:        vs->vm_dsize = (dsize+bsize)/NBPG;      /* data size (pages) XXX */
        !           273:        vs->vm_ssize = MAXSSIZ/NBPG;    /* stack size (pages) */
        !           274:        vs->vm_taddr = 0;       /* user virtual address of text XXX */
        !           275:        vs->vm_daddr = (caddr_t)tsize;  /* user virtual address of data XXX */
        !           276:        /* user VA at max stack growth */
        !           277:        vs->vm_maxsaddr = (caddr_t)(USRSTACK - MAXSSIZ);
        !           278: 
        !           279:        /* everything fits in a single page, no fixups, no more work */
        !           280:        /* (groan) due to bug in vm_map_copy, can't remap. copy for now. */
        !           281:        rv = copyout((caddr_t)org, (caddr_t)USRSTACK - NBPG, NBPG);
        !           282:        if(rv)
        !           283:                goto exec_abort;
        !           284: 
        !           285:        /* close files on exec, fixup signals */
        !           286:        fdcloseexec(p);
        !           287:        execsigs(p);
        !           288: 
        !           289:        p->p_regs[SP] = USRSTACK - NBPG + NBPG/4 - 4;
        !           290:        vs->vm_ssize = 1;       /* stack size (pages) */
        !           291:        setregs(p, hdr.a_entry);
        !           292:        kmem_free_wakeup(exec_map, org, (NCARGS + PAGE_SIZE)/PAGE_SIZE);
        !           293:        vput(ndp->ni_vp);
        !           294:        return (0);
        !           295: 
        !           296: exec_fail:
        !           297:        vput(ndp->ni_vp);
        !           298:        return(rv);
        !           299: 
        !           300: exec_abort:
        !           301:        /* untested and probably bogus */
        !           302:        kmem_free_wakeup(exec_map, org, (NCARGS + PAGE_SIZE)/PAGE_SIZE);
        !           303:        vput(ndp->ni_vp);
        !           304:        exit(p, W_EXITCODE(0, SIGABRT));
        !           305:        return(0);
        !           306: 
        !           307: }

unix.superglobalmegacorp.com

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