No empty .Rs/.Re
[netbsd-mini2440.git] / sys / kern / kern_execve
blob4e92d33f3d8f141aee087d267ca37300ad4a86d6
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  */
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"
32 #include "vm/vm.h"
33 #include "vm/vm_param.h"
34 #include "vm/vm_map.h"
35 #include "vm/vm_kern.h"
37 #include "machine/reg.h"
39 static char rcsid[] = "$Header: /pub/NetBSD/misc/repositories/cvsroot/src/sys/kern/Attic/kern_execve,v 1.1 1993/03/21 09:46:30 cgd Exp $";
42  * Bill's first-cut execve() system call. Puts hair on your chest.
43  */
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;
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;
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;
77         /* is it there? */
78         if (rv = namei(ndp, p))
79                 return (rv);
81         /* is it a regular file? */
82         if (ndp->ni_vp->v_type != VREG) {
83                 vput(ndp->ni_vp);
84                 return(ENOEXEC);
85         }
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;
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);
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;
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;
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;
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          */
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          */
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;
159         /* first, do args */
160         needsenv = 1;
161         vectp = uap->argp;
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                 }
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);
198 dont_bother:
199         if (limitonargs <= 0) {
200                 rv = E2BIG;
201                 goto exec_fail;
202         }
204         if (needsenv) {
205                 argc = cnt;
206                 vectp = uap->envp;
207                 needsenv = 0;
208                 goto do_env_as_well;
209         }
211         kargbuf[-1] = (char *)argc;
213         /*
214          * Step 4. Build the new processes image.
215          */
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;
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;
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;
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         }
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;
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;
266         /*
267          * Step 5. Prepare process for execution.
268          */
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);
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;
285         /* close files on exec, fixup signals */
286         fdcloseexec(p);
287         execsigs(p);
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);
296 exec_fail:
297         vput(ndp->ni_vp);
298         return(rv);
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);