Annotation of Net2/kern/kern_execve, revision 1.1.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.