|
|
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:
1.1.1.2 ! root 39: static char rcsid[] = "$Header: /cvsroot/src/sys/kern/Attic/kern_execve,v 1.1.1.1 1993/03/21 09:46:31 cgd Exp $";
1.1 root 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.