Make kmstartup and mcount void functions.
[unix-history] / sys / kern / kern_execve.c
CommitLineData
15637ed4 1/*
317350b1 2 * Copyright (c) 1993, David Greenman
15637ed4
RG
3 * All rights reserved.
4 *
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:
317350b1
DG
15 * This product includes software developed by David Greenman
16 * 4. The name of the developer may be used to endorse or promote products
17 * derived from this software without specific prior written permission.
15637ed4 18 *
317350b1 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15637ed4
RG
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
317350b1 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
15637ed4
RG
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 *
fde1aeb2 31 * $Id: kern_execve.c,v 1.10 1993/12/12 12:23:19 davidg Exp $
15637ed4
RG
32 */
33
34#include "param.h"
35#include "systm.h"
36#include "signalvar.h"
37#include "resourcevar.h"
317350b1 38#include "imgact.h"
15637ed4 39#include "mount.h"
15637ed4 40#include "file.h"
7d69de6f 41#include "acct.h"
15637ed4
RG
42#include "exec.h"
43#include "stat.h"
44#include "wait.h"
45#include "mman.h"
46#include "malloc.h"
317350b1 47#include "syslog.h"
15637ed4
RG
48
49#include "vm/vm.h"
50#include "vm/vm_param.h"
51#include "vm/vm_map.h"
52#include "vm/vm_kern.h"
fde1aeb2 53#include "vm/vm_user.h"
15637ed4
RG
54
55#include "machine/reg.h"
56
317350b1
DG
57int exec_extract_strings __P((struct image_params *));
58caddr_t exec_copyout_strings __P((struct image_params *));
59
60int exec_aout_imgact __P((struct image_params *));
61int exec_shell_imgact __P((struct image_params *));
62
63struct execsw {
64 int (*imgact) __P((struct image_params *));
65};
66
67struct execsw execsw[] = {
68 { exec_aout_imgact },
69 { exec_shell_imgact },
70 { NULL },
71 { NULL },
72 { NULL },
73 { NULL },
74 { NULL },
75 { NULL },
76};
15637ed4
RG
77
78/*
79 * execve() system call.
80 */
81
4c45483e 82int
15637ed4
RG
83execve(p, uap, retval)
84 struct proc *p;
3c7eb27c 85 register struct execve_args *uap;
15637ed4
RG
86 int *retval;
87{
317350b1
DG
88 struct nameidata nd, *ndp;
89 char *stringbase, *stringp, *stack_base;
90 int error, resid, len, i;
91#if 0
92 char image_header[256];
93#endif
94 struct image_params image_params, *iparams;
95 struct vnode *vnodep;
15637ed4 96 struct vattr attr;
317350b1
DG
97 char *image_header;
98
99 iparams = &image_params;
100 bzero((caddr_t)iparams, sizeof(struct image_params));
101 image_header = (char *)0;
15637ed4
RG
102
103 /*
317350b1
DG
104 * Initialize a few constants in the common area
105 */
106 iparams->proc = p;
107 iparams->uap = uap;
108 iparams->attr = &attr;
109
110 /*
111 * Allocate temporary demand zeroed space for argument and
112 * environment strings
113 */
fde1aeb2
GW
114 error = vm_allocate(kernel_map, (vm_offset_t *)&iparams->stringbase,
115 ARG_MAX, TRUE);
317350b1
DG
116 if (error) {
117 log(LOG_WARNING, "execve: failed to allocate string space\n");
118 return (error);
119 }
120
121 if (!iparams->stringbase) {
122 error = ENOMEM;
123 goto exec_fail;
124 }
125 iparams->stringp = iparams->stringbase;
126 iparams->stringspace = ARG_MAX;
127
128 /*
129 * Translate the file name. namei() returns a vnode pointer
130 * in ni_vp amoung other things.
15637ed4
RG
131 */
132 ndp = &nd;
317350b1 133 ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW | SAVENAME;
15637ed4
RG
134 ndp->ni_segflg = UIO_USERSPACE;
135 ndp->ni_dirp = uap->fname;
136
317350b1 137interpret:
15637ed4 138
317350b1
DG
139 error = namei(ndp, p);
140 if (error) {
fde1aeb2
GW
141 vm_deallocate(kernel_map, (vm_offset_t)iparams->stringbase,
142 ARG_MAX);
317350b1 143 goto exec_fail;
15637ed4 144 }
15637ed4 145
317350b1 146 iparams->vnodep = vnodep = ndp->ni_vp;
15637ed4 147
317350b1
DG
148 if (vnodep == NULL) {
149 error = ENOEXEC;
150 goto exec_fail_dealloc;
15637ed4
RG
151 }
152
153 /*
317350b1 154 * Check file permissions (also 'opens' file)
15637ed4 155 */
317350b1
DG
156 error = exec_check_permissions(iparams);
157 if (error)
158 goto exec_fail_dealloc;
15637ed4 159
317350b1
DG
160#if 0
161 /*
162 * Read the image header from the file.
163 */
164 error = vn_rdwr(UIO_READ,
165 vnodep,
166 image_header,
167 sizeof(image_header),
168 0,
169 UIO_SYSSPACE, IO_NODELOCKED,
170 p->p_ucred,
171 &resid,
172 p);
173 if (error)
174 goto exec_fail_dealloc;
175
176 /* Clear out junk in image_header if a partial read (small file) */
177 if (resid)
178 bzero(image_header + (sizeof(image_header) - resid), resid);
179#endif
180 /*
181 * Map the image header (first page) of the file into
182 * kernel address space
183 */
fde1aeb2
GW
184 error = vm_mmap(kernel_map, /* map */
185 (vm_offset_t *)&image_header, /* address */
186 NBPG, /* size */
187 VM_PROT_READ, /* protection */
188 VM_PROT_READ, /* max protection */
189 MAP_FILE, /* flags */
190 (caddr_t)vnodep, /* vnode */
191 0); /* offset */
317350b1 192 if (error) {
fde1aeb2 193 printf("mmap failed: %d\n",error);
317350b1 194 goto exec_fail_dealloc;
15637ed4 195 }
317350b1
DG
196 iparams->image_header = image_header;
197
198 /*
199 * Loop through list of image activators, calling each one.
200 * If there is no match, the activator returns -1. If there
201 * is a match, but there was an error during the activation,
202 * the error is returned. Otherwise 0 means success. If the
203 * image is interpreted, loop back up and try activating
204 * the interpreter.
205 */
206 for (i = 0; i < sizeof(execsw)/sizeof(execsw[0]); ++i) {
207 if (execsw[i].imgact)
208 error = (*execsw[i].imgact)(iparams);
209 else
210 continue;
211
212 if (error == -1)
213 continue;
214 if (error)
215 goto exec_fail_dealloc;
216 if (iparams->interpreted) {
217 /* free old vnode and name buffer */
33f2dd50
DG
218 vput(ndp->ni_vp);
219 FREE(ndp->ni_pnbuf, M_NAMEI);
fde1aeb2
GW
220 if (vm_deallocate(kernel_map,
221 (vm_offset_t)image_header, NBPG))
317350b1 222 panic("execve: header dealloc failed (1)");
33f2dd50 223
317350b1 224 /* set new name to that of the interpreter */
33f2dd50 225 ndp->ni_segflg = UIO_SYSSPACE;
317350b1
DG
226 ndp->ni_dirp = iparams->interpreter_name;
227 ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW | SAVENAME;
228 goto interpret;
15637ed4 229 }
317350b1
DG
230 break;
231 }
232 /* If we made it through all the activators and none matched, exit. */
233 if (error == -1) {
234 error = ENOEXEC;
235 goto exec_fail_dealloc;
15637ed4
RG
236 }
237
317350b1
DG
238 /*
239 * Copy out strings (args and env) and initialize stack base
240 */
241 stack_base = exec_copyout_strings(iparams);
242 p->p_vmspace->vm_minsaddr = stack_base;
243 p->p_regs[SP] = (int) stack_base;
15637ed4 244
317350b1 245 p->p_vmspace->vm_ssize = (((caddr_t)USRSTACK - stack_base) >> PAGE_SHIFT) + 1;
15637ed4 246
317350b1
DG
247 /*
248 * Stuff argument count as first item on stack
249 */
250 p->p_regs[SP] -= sizeof(int);
251 *(int *)(p->p_regs[SP]) = iparams->argc;
15637ed4 252
317350b1
DG
253 /* close files on exec, fixup signals */
254 fdcloseexec(p);
255 execsigs(p);
15637ed4 256
317350b1
DG
257 /* name this process - nameiexec(p, ndp) */
258 len = MIN(ndp->ni_namelen,MAXCOMLEN);
259 bcopy(ndp->ni_ptr, p->p_comm, len);
260 p->p_comm[len] = 0;
15637ed4
RG
261
262 /*
317350b1
DG
263 * mark as executable, wakeup any process that was vforked and tell
264 * it that it now has it's own resources back
15637ed4 265 */
317350b1
DG
266 p->p_flag |= SEXEC;
267 if (p->p_pptr && (p->p_flag & SPPWAIT)) {
268 p->p_flag &= ~SPPWAIT;
269 wakeup((caddr_t)p->p_pptr);
270 }
271
272 /* implement set userid/groupid */
273 if ((attr.va_mode&VSUID) && (p->p_flag & STRC) == 0) {
274 p->p_ucred = crcopy(p->p_ucred);
275 p->p_cred->p_svuid = p->p_ucred->cr_uid = attr.va_uid;
276 }
277 if ((attr.va_mode&VSGID) && (p->p_flag & STRC) == 0) {
278 p->p_ucred = crcopy(p->p_ucred);
279 p->p_cred->p_svgid = p->p_ucred->cr_groups[0] = attr.va_gid;
280 }
281
282 /* mark vnode pure text */
283 ndp->ni_vp->v_flag |= VTEXT;
15637ed4
RG
284
285 /*
317350b1
DG
286 * If tracing the process, trap to debugger so breakpoints
287 * can be set before the program executes.
15637ed4 288 */
317350b1
DG
289 if (p->p_flag & STRC)
290 psignal(p, SIGTRAP);
15637ed4 291
317350b1
DG
292 /* clear "fork but no exec" flag, as we _are_ execing */
293 p->p_acflag &= ~AFORK;
15637ed4 294
317350b1
DG
295 /* Set entry address */
296 setregs(p, iparams->entry_addr);
15637ed4 297
317350b1
DG
298 /*
299 * free various allocated resources
300 */
fde1aeb2
GW
301 if (vm_deallocate(kernel_map, (vm_offset_t)iparams->stringbase,
302 ARG_MAX))
317350b1 303 panic("execve: string buffer dealloc failed (1)");
fde1aeb2 304 if (vm_deallocate(kernel_map, (vm_offset_t)image_header, NBPG))
317350b1
DG
305 panic("execve: header dealloc failed (2)");
306 vput(ndp->ni_vp);
307 FREE(ndp->ni_pnbuf, M_NAMEI);
15637ed4 308
317350b1 309 return (0);
15637ed4 310
317350b1
DG
311exec_fail_dealloc:
312 if (iparams->stringbase && iparams->stringbase != (char *)-1)
fde1aeb2
GW
313 if (vm_deallocate(kernel_map, (vm_offset_t)iparams->stringbase,
314 ARG_MAX))
317350b1
DG
315 panic("execve: string buffer dealloc failed (2)");
316 if (iparams->image_header && iparams->image_header != (char *)-1)
fde1aeb2
GW
317 if (vm_deallocate(kernel_map,
318 (vm_offset_t)iparams->image_header, NBPG))
317350b1
DG
319 panic("execve: header dealloc failed (3)");
320 vput(ndp->ni_vp);
321 FREE(ndp->ni_pnbuf, M_NAMEI);
15637ed4 322
317350b1
DG
323exec_fail:
324 if (iparams->vmspace_destroyed) {
325 /* sorry, no more process anymore. exit gracefully */
326#if 0 /* XXX */
327 vm_deallocate(&vs->vm_map, USRSTACK - MAXSSIZ, MAXSSIZ);
328#endif
329 kexit(p, W_EXITCODE(0, SIGABRT));
330 /* NOT REACHED */
331 return(0);
332 } else {
333 return(error);
15637ed4 334 }
317350b1 335}
15637ed4 336
317350b1
DG
337/*
338 * Destroy old address space, and allocate a new stack
339 * The new stack is only DFLSSIZ large because it is grown
340 * automatically in trap.c.
341 */
342int
343exec_new_vmspace(iparams)
344 struct image_params *iparams;
345{
346 int error;
347 struct vmspace *vmspace = iparams->proc->p_vmspace;
348 caddr_t stack_addr = (caddr_t) (USRSTACK - DFLSSIZ);
15637ed4 349
317350b1 350 iparams->vmspace_destroyed = 1;
15637ed4 351
317350b1
DG
352 /* Blow away entire process VM */
353 vm_deallocate(&vmspace->vm_map, 0, USRSTACK);
15637ed4 354
317350b1 355 /* Allocate a new stack */
fde1aeb2
GW
356 error = vm_allocate(&vmspace->vm_map, (vm_offset_t *)&stack_addr,
357 DFLSSIZ, FALSE);
317350b1
DG
358 if (error)
359 return(error);
15637ed4 360
317350b1
DG
361 /* Initialize maximum stack address */
362 vmspace->vm_maxsaddr = (char *)USRSTACK - MAXSSIZ;
15637ed4 363
317350b1
DG
364 return(0);
365}
15637ed4 366
317350b1
DG
367/*
368 * Copy out argument and environment strings from the old process
369 * address space into the temporary string buffer.
370 */
371int
372exec_extract_strings(iparams)
373 struct image_params *iparams;
374{
375 char **argv, **envv;
376 char *argp, *envp;
377 int length;
33f2dd50 378
317350b1
DG
379 /*
380 * extract arguments first
381 */
33f2dd50 382
317350b1
DG
383 argv = iparams->uap->argv;
384
385 if (argv)
386 while (argp = (caddr_t) fuword(argv++)) {
387 if (argp == (caddr_t) -1)
388 return (EFAULT);
389 if (copyinstr(argp, iparams->stringp, iparams->stringspace,
390 &length) == ENAMETOOLONG)
391 return(E2BIG);
392 iparams->stringspace -= length;
393 iparams->stringp += length;
394 iparams->argc++;
395 }
15637ed4 396
317350b1
DG
397 /*
398 * extract environment strings
399 */
15637ed4 400
317350b1
DG
401 envv = iparams->uap->envv;
402
403 if (envv)
404 while (envp = (caddr_t) fuword(envv++)) {
405 if (envp == (caddr_t) -1)
406 return (EFAULT);
407 if (copyinstr(envp, iparams->stringp, iparams->stringspace,
408 &length) == ENAMETOOLONG)
409 return(E2BIG);
410 iparams->stringspace -= length;
411 iparams->stringp += length;
412 iparams->envc++;
413 }
33f2dd50 414
317350b1
DG
415 return (0);
416}
15637ed4 417
317350b1
DG
418/*
419 * Copy strings out to the new process address space, constructing
420 * new arg and env vector tables. Return a pointer to the base
421 * so that it can be used as the initial stack pointer.
422 */
423caddr_t
424exec_copyout_strings(iparams)
425 struct image_params *iparams;
426{
427 int argc, envc;
428 char **vectp;
429 char *stack_base, *stringp, *destp;
430 int vect_table_size, string_table_size;
15637ed4
RG
431
432 /*
317350b1
DG
433 * Calculate string base and vector table pointers.
434 */
435 destp = (caddr_t) ((caddr_t)USRSTACK -
436 roundup((ARG_MAX - iparams->stringspace), sizeof(char *)));
437 /*
438 * The '+ 2' is for the null pointers at the end of each of the
439 * arg and env vector sets
15637ed4 440 */
317350b1
DG
441 vectp = (char **) (destp -
442 (iparams->argc + iparams->envc + 2) * sizeof(char *));
15637ed4 443
317350b1
DG
444 /*
445 * vectp also becomes our initial stack base
446 */
447 stack_base = (caddr_t)vectp;
15637ed4 448
317350b1
DG
449 stringp = iparams->stringbase;
450 argc = iparams->argc;
451 envc = iparams->envc;
15637ed4 452
317350b1
DG
453 for (; argc > 0; --argc) {
454 *(vectp++) = destp;
455 while (*destp++ = *stringp++);
15637ed4 456 }
317350b1
DG
457
458 /* a null vector table pointer seperates the argp's from the envp's */
459 *(vectp++) = NULL;
460
461 for (; envc > 0; --envc) {
462 *(vectp++) = destp;
463 while (*destp++ = *stringp++);
15637ed4
RG
464 }
465
317350b1
DG
466 /* end of vector table is a null pointer */
467 *vectp = NULL;
15637ed4 468
317350b1
DG
469 return (stack_base);
470}
15637ed4 471
317350b1
DG
472/*
473 * Check permissions of file to execute.
474 * Return 0 for success or error code on failure.
475 */
476int
477exec_check_permissions(iparams)
478 struct image_params *iparams;
479{
480 struct proc *p = iparams->proc;
481 struct vnode *vnodep = iparams->vnodep;
482 struct vattr *attr = iparams->attr;
483 int error;
15637ed4 484
317350b1
DG
485 /*
486 * Check number of open-for-writes on the file and deny execution
487 * if there are any.
488 */
489 if (vnodep->v_writecount) {
490 return (ETXTBSY);
491 }
15637ed4 492
317350b1
DG
493 /* Get file attributes */
494 error = VOP_GETATTR(vnodep, attr, p->p_ucred, p);
495 if (error)
496 return (error);
15637ed4 497
317350b1
DG
498 /*
499 * 1) Check if file execution is disabled for the filesystem that this
500 * file resides on.
501 * 2) Insure that at least one execute bit is on - otherwise root
502 * will always succeed, and we don't want to happen unless the
503 * file really is executable.
504 * 3) Insure that the file is a regular file.
505 */
506 if ((vnodep->v_mount->mnt_flag & MNT_NOEXEC) ||
507 ((attr->va_mode & 0111) == 0) ||
508 (attr->va_type != VREG)) {
509 return (EACCES);
510 }
15637ed4 511
317350b1
DG
512 /*
513 * Disable setuid/setgid if the filesystem prohibits it or if
514 * the process is being traced.
515 */
516 if ((vnodep->v_mount->mnt_flag & MNT_NOSUID) || (p->p_flag & STRC))
517 attr->va_mode &= ~(VSUID | VSGID);
15637ed4 518
317350b1
DG
519 /*
520 * Check for execute permission to file based on current credentials.
521 * Then call filesystem specific open routine (which does nothing
522 * in the general case).
523 */
524 error = VOP_ACCESS(vnodep, VEXEC, p->p_ucred, p);
525 if (error)
526 return (error);
15637ed4 527
317350b1
DG
528 error = VOP_OPEN(vnodep, FREAD, p->p_ucred, p);
529 if (error)
530 return (error);
15637ed4 531
317350b1 532 return (0);
15637ed4 533}