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