|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.