]> git.saurik.com Git - apple/xnu.git/blame - bsd/kern/kern_exec.c
xnu-201.19.tar.gz
[apple/xnu.git] / bsd / kern / kern_exec.c
CommitLineData
1c79356b
A
1/*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22/* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
23/*
24 * Mach Operating System
25 * Copyright (c) 1987 Carnegie-Mellon University
26 * All rights reserved. The CMU software License Agreement specifies
27 * the terms and conditions for use and redistribution.
28 */
29
30#include <cputypes.h>
31
32/*-
33 * Copyright (c) 1982, 1986, 1991, 1993
34 * The Regents of the University of California. All rights reserved.
35 * (c) UNIX System Laboratories, Inc.
36 * All or some portions of this file are derived from material licensed
37 * to the University of California by American Telephone and Telegraph
38 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
39 * the permission of UNIX System Laboratories, Inc.
40 *
41 * Redistribution and use in source and binary forms, with or without
42 * modification, are permitted provided that the following conditions
43 * are met:
44 * 1. Redistributions of source code must retain the above copyright
45 * notice, this list of conditions and the following disclaimer.
46 * 2. Redistributions in binary form must reproduce the above copyright
47 * notice, this list of conditions and the following disclaimer in the
48 * documentation and/or other materials provided with the distribution.
49 * 3. All advertising materials mentioning features or use of this software
50 * must display the following acknowledgement:
51 * This product includes software developed by the University of
52 * California, Berkeley and its contributors.
53 * 4. Neither the name of the University nor the names of its contributors
54 * may be used to endorse or promote products derived from this software
55 * without specific prior written permission.
56 *
57 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
58 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
59 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
60 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
61 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
62 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
63 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
64 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
65 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
66 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
67 * SUCH DAMAGE.
68 *
69 * from: @(#)kern_exec.c 8.1 (Berkeley) 6/10/93
70 */
71#include <machine/reg.h>
72
73#include <sys/param.h>
74#include <sys/systm.h>
75#include <sys/filedesc.h>
76#include <sys/kernel.h>
77#include <sys/proc.h>
78#include <sys/user.h>
79#include <sys/buf.h>
80#include <sys/socketvar.h>
81#include <sys/malloc.h>
82#include <sys/namei.h>
83#include <sys/mount.h>
84#include <sys/vnode.h>
85#include <sys/file.h>
86#include <sys/stat.h>
87#include <sys/uio.h>
88#include <sys/acct.h>
89#include <sys/exec.h>
90#include <sys/kdebug.h>
91#include <sys/signal.h>
92
93#include <mach/vm_param.h>
94
95#include <vm/vm_map.h>
96#include <vm/vm_kern.h>
97
98#include <kern/thread.h>
99#include <kern/task.h>
100
101#include <kern/ast.h>
102#include <kern/mach_loader.h>
103#include <mach-o/fat.h>
104#include <mach-o/loader.h>
105#include <machine/vmparam.h>
106
107extern vm_map_t bsd_pageable_map;
108
109#define ROUND_PTR(type, addr) \
110 (type *)( ( (unsigned)(addr) + 16 - 1) \
111 & ~(16 - 1) )
112
113static int load_return_to_errno(load_return_t lrtn);
114int execve(struct proc *p, struct execve_args *uap, register_t *retval);
765c9de3
A
115static int execargs_alloc(vm_offset_t *addrp);
116static int execargs_free(vm_offset_t addr);
1c79356b
A
117
118int
119execv(p, args, retval)
120 struct proc *p;
121 void *args;
122 int *retval;
123{
124 ((struct execve_args *)args)->envp = NULL;
125 return (execve(p, args, retval));
126}
127
128/* ARGSUSED */
129int
130execve(p, uap, retval)
131 register struct proc *p;
132 register struct execve_args *uap;
133 register_t *retval;
134{
135 register struct ucred *cred = p->p_ucred;
136 register struct filedesc *fdp = p->p_fd;
137 register nc;
138 register char *cp;
139 int na, ne, ucp, ap, cc;
140 unsigned len;
141 int indir;
142 char *sharg;
143 char *execnamep;
144 struct vnode *vp;
145 struct vattr vattr;
146 struct vattr origvattr;
147 vm_offset_t execargs;
148 struct nameidata nd;
149 struct ps_strings ps;
150#define SHSIZE 512
151 char cfarg[SHSIZE];
152 boolean_t is_fat;
153 kern_return_t ret;
154 struct mach_header *mach_header;
155 struct fat_header *fat_header;
156 struct fat_arch fat_arch;
157 load_return_t lret;
158 load_result_t load_result;
159 struct uthread *uthread;
0b4e3aa0
A
160 vm_map_t old_map;
161 vm_map_t map;
1c79356b
A
162 int i;
163 union {
164 /* #! and name of interpreter */
165 char ex_shell[SHSIZE];
166 /* Mach-O executable */
167 struct mach_header mach_header;
168 /* Fat executable */
169 struct fat_header fat_header;
170 char pad[512];
171 } exdata;
172 int resid, error;
173 char *savedpath;
174 int savedpathlen = 0;
175 vm_offset_t *execargsp;
176 char *cpnospace;
0b4e3aa0
A
177 task_t task;
178 task_t new_task;
179 thread_act_t thr_act;
1c79356b 180 int numthreads;
0b4e3aa0
A
181 int vfexec=0;
182 unsigned long arch_offset =0;
183 unsigned long arch_size = 0;
1c79356b 184
0b4e3aa0
A
185 task = current_task();
186 thr_act = current_act();
187 uthread = get_bsdthread_info(thr_act);
1c79356b 188
0b4e3aa0
A
189 if (uthread->uu_flag & P_VFORK) {
190 vfexec = 1; /* Mark in exec */
191 } else {
192 if (task != kernel_task) {
193 numthreads = get_task_numacts(task);
194 if (numthreads <= 0 )
195 return(EINVAL);
196 if (numthreads > 1) {
197 return(EOPNOTSUPP);
198 }
1c79356b
A
199 }
200 }
201
765c9de3
A
202 error = execargs_alloc(&execargs);
203 if (error)
204 return(error);
1c79356b 205
1c79356b
A
206 savedpath = execargs;
207
208 /*
209 * To support new app package launching for Mac OS X, the dyld
210 * needs the first argument to execve() stored on the user stack.
211 * Copyin the "path" at the begining of the "execargs" buffer
212 * allocated above.
213 *
214 * We have to do this before namei() because in case of
215 * symbolic links, namei() would overwrite the original "path".
216 * In case the last symbolic link resolved was a relative pathname
217 * we would loose the original "path", which could be an
218 * absolute pathname. This might be unacceptable for dyld.
219 */
220 /* XXX We could optimize to avoid copyinstr in the namei() */
221
222 error = copyinstr(uap->fname, savedpath, MAXPATHLEN, &savedpathlen);
223 if (error)
224 return (error);
225 /*
226 * copyinstr will put in savedpathlen, the count of
227 * characters (including NULL) in the path.
228 */
229
230 /* Save the name aside for future use */
231 execargsp = (vm_offset_t *)((char *)(execargs) + savedpathlen);
232
233 NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | SAVENAME,
234 UIO_USERSPACE, uap->fname, p);
235 if ((error = namei(&nd)))
236 goto bad1;
237 vp = nd.ni_vp;
238 VOP_LEASE(vp, p, p->p_ucred, LEASE_READ);
239
240 if ((error = VOP_GETATTR(vp, &origvattr, p->p_ucred, p)))
241 goto bad;
242
243 /* Check mount point */
244 if (vp->v_mount->mnt_flag & MNT_NOEXEC) {
245 error = EACCES;
246 goto bad;
247 }
248
249 indir = 0;
250 if ((vp->v_mount->mnt_flag & MNT_NOSUID) || (p->p_flag & P_TRACED))
251 origvattr.va_mode &= ~(VSUID | VSGID);
252
253 *(&vattr) = *(&origvattr);
254
255again:
256 error = check_exec_access(p, vp, &vattr);
257 if (error)
258 goto bad;
259
260 /*
261 * Read in first few bytes of file for segment sizes, magic number:
262 * 407 = plain executable
263 * 410 = RO text
264 * 413 = demand paged RO text
265 * Also an ASCII line beginning with #! is
266 * the file name of a ``shell'' and arguments may be prepended
267 * to the argument list if given here.
268 *
269 * SHELL NAMES ARE LIMITED IN LENGTH.
270 *
271 * ONLY ONE ARGUMENT MAY BE PASSED TO THE SHELL FROM
272 * THE ASCII LINE.
273 */
274
275 exdata.ex_shell[0] = '\0'; /* for zero length files */
276
277 error = vn_rdwr(UIO_READ, vp, (caddr_t)&exdata, sizeof (exdata), 0,
278 UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid, p);
279
280 if (error)
281 goto bad;
282
283#ifndef lint
284 if (resid > sizeof(exdata) - min(sizeof(exdata.mach_header),
285 sizeof(exdata.fat_header))
286 && exdata.ex_shell[0] != '#') {
287 error = ENOEXEC;
288 goto bad;
289 }
290#endif /* lint */
291 mach_header = &exdata.mach_header;
292 fat_header = &exdata.fat_header;
293 if (mach_header->magic == MH_MAGIC)
294 is_fat = FALSE;
295 else if (fat_header->magic == FAT_MAGIC ||
296 fat_header->magic == FAT_CIGAM)
297 is_fat = TRUE;
298 else if (mach_header->magic == MH_CIGAM) {
299 error = EBADARCH;
300 goto bad;
301 } else {
302 if (exdata.ex_shell[0] != '#' ||
303 exdata.ex_shell[1] != '!' ||
304 indir) {
305 error = ENOEXEC;
306 goto bad;
307 }
308 cp = &exdata.ex_shell[2]; /* skip "#!" */
309 while (cp < &exdata.ex_shell[SHSIZE]) {
310 if (*cp == '\t')
311 *cp = ' ';
312 else if (*cp == '\n') {
313 *cp = '\0';
314 break;
315 }
316 cp++;
317 }
318 if (*cp != '\0') {
319 error = ENOEXEC;
320 goto bad;
321 }
322 cp = &exdata.ex_shell[2];
323 while (*cp == ' ')
324 cp++;
325 execnamep = cp;
326 while (*cp && *cp != ' ')
327 cp++;
328 cfarg[0] = '\0';
329 cpnospace = cp;
330 if (*cp) {
331 *cp++ = '\0';
332 while (*cp == ' ')
333 cp++;
334 if (*cp)
335 bcopy((caddr_t)cp, (caddr_t)cfarg, SHSIZE);
336 }
337
338 /*
339 * Support for new app package launching for Mac OS X.
340 * We are about to retry the execve() by changing the path to the
341 * interpreter name. Need to re-initialize the savedpath and
342 * savedpathlen. +1 for NULL.
343 */
344 savedpathlen = (cpnospace - execnamep + 1);
345 error = copystr(execnamep, savedpath, savedpathlen, &savedpathlen);
346 if (error)
347 goto bad;
348
349 /* Save the name aside for future use */
350 execargsp = (vm_offset_t *)((char *)(execargs) + savedpathlen);
351
352 indir = 1;
353 vput(vp);
354 nd.ni_cnd.cn_nameiop = LOOKUP;
355 nd.ni_cnd.cn_flags = (nd.ni_cnd.cn_flags & HASBUF) |
356 (FOLLOW | LOCKLEAF | SAVENAME);
357 nd.ni_segflg = UIO_SYSSPACE;
358 nd.ni_dirp = execnamep;
359 if ((error = namei(&nd)))
360 goto bad1;
361 vp = nd.ni_vp;
362 VOP_LEASE(vp, p, cred, LEASE_READ);
363 if ((error = VOP_GETATTR(vp, &vattr, p->p_ucred, p)))
364 goto bad;
365 goto again;
366 }
367
368 /*
369 * Collect arguments on "file" in swap space.
370 */
371 na = 0;
372 ne = 0;
373 nc = 0;
374 cc = 0;
375 /*
376 * Support for new app package launching for Mac OS X allocates
377 * the "path" at the begining.
378 * execargs get allocated after that
379 */
380 cp = (char *) execargsp; /* running pointer for copy */
381 /*
382 * size of execargs less sizeof "path",
383 * a pointer to "path" and a NULL poiter
384 */
385 cc = NCARGS - savedpathlen - 2*NBPW;
386 /*
387 * Copy arguments into file in argdev area.
388 */
389 if (uap->argp) for (;;) {
390 ap = NULL;
391 sharg = NULL;
392 if (indir && na == 0) {
393 sharg = nd.ni_cnd.cn_nameptr;
394 ap = (int)sharg;
395 uap->argp++; /* ignore argv[0] */
396 } else if (indir && (na == 1 && cfarg[0])) {
397 sharg = cfarg;
398 ap = (int)sharg;
399 } else if (indir && (na == 1 || (na == 2 && cfarg[0])))
400 ap = (int)uap->fname;
401 else if (uap->argp) {
402 ap = fuword((caddr_t)uap->argp);
403 uap->argp++;
404 }
405 if (ap == NULL && uap->envp) {
406 uap->argp = NULL;
407 if ((ap = fuword((caddr_t)uap->envp)) != NULL)
408 uap->envp++, ne++;
409 }
410 if (ap == NULL)
411 break;
412 na++;
413 if (ap == -1) {
414 error = EFAULT;
415 break;
416 }
417 do {
418 if (nc >= (NCARGS - savedpathlen - 2*NBPW -1)) {
419 error = E2BIG;
420 break;
421 }
422 if (sharg) {
423 error = copystr(sharg, cp, (unsigned)cc, &len);
424 sharg += len;
425 } else {
426 error = copyinstr((caddr_t)ap, cp, (unsigned)cc,
427 &len);
428 ap += len;
429 }
430 cp += len;
431 nc += len;
432 cc -= len;
433 } while (error == ENAMETOOLONG);
434 if (error) {
435 goto bad;
436 }
437 }
438 nc = (nc + NBPW-1) & ~(NBPW-1);
439
440 /*
441 * If we have a fat file, find "our" executable.
442 */
443 if (is_fat) {
444 /*
445 * Look up our architecture in the fat file.
446 */
447 lret = fatfile_getarch(vp, (vm_offset_t)fat_header, &fat_arch);
448 if (lret != LOAD_SUCCESS) {
449 error = load_return_to_errno(lret);
450 goto bad;
451 }
452 /* Read the Mach-O header out of it */
453 error = vn_rdwr(UIO_READ, vp, (caddr_t)&exdata.mach_header,
454 sizeof (exdata.mach_header),
455 fat_arch.offset,
456 UIO_SYSSPACE, (IO_UNIT|IO_NODELOCKED), cred, &resid, p);
457
458 if (error) {
459 goto bad;
460 }
461
462 /* Did we read a complete header? */
463 if (resid) {
464 error = EBADEXEC;
465 goto bad;
466 }
467
468 /* Is what we found a Mach-O executable */
469 if (mach_header->magic != MH_MAGIC) {
470 error = ENOEXEC;
471 goto bad;
472 }
473
0b4e3aa0
A
474 arch_offset = fat_arch.offset;
475 arch_size = fat_arch.size;
1c79356b
A
476 } else {
477 /*
478 * Load the Mach-O file.
479 */
0b4e3aa0
A
480 arch_offset = 0;
481 arch_size = (u_long)vattr.va_size;
482 }
483
484 if (vfexec) {
485 kern_return_t result;
486
487 result = task_create_local(task, FALSE, FALSE, &new_task);
488 if (result != KERN_SUCCESS)
489 printf("execve: task_create failed. Code: 0x%x\n", result);
490 p->task = new_task;
491 set_bsdtask_info(new_task, p);
492 task = new_task;
493 map = get_task_map(new_task);
494 result = thread_create(new_task, &thr_act);
495 if (result != KERN_SUCCESS)
496 printf("execve: thread_create failed. Code: 0x%x\n", result);
497 uthread = get_bsdthread_info(thr_act);
498 } else {
499 map = VM_MAP_NULL;
500
1c79356b
A
501 }
502
0b4e3aa0
A
503 /*
504 * Load the Mach-O file.
505 */
506 VOP_UNLOCK(vp, 0, p);
507 lret = load_machfile(vp, mach_header, arch_offset,
508 arch_size, &load_result, thr_act, map);
509
1c79356b
A
510 if (lret != LOAD_SUCCESS) {
511 error = load_return_to_errno(lret);
0b4e3aa0 512 goto badtoolate;
1c79356b
A
513 }
514
515 /* load_machfile() maps the vnode */
516 ubc_map(vp);
517
518 /*
519 * deal with set[ug]id.
520 */
521 p->p_flag &= ~P_SUGID;
522 if (((origvattr.va_mode & VSUID) != 0 &&
523 p->p_ucred->cr_uid != origvattr.va_uid)
524 || (origvattr.va_mode & VSGID) != 0 &&
525 p->p_ucred->cr_gid != origvattr.va_gid) {
526 p->p_ucred = crcopy(cred);
527#if KTRACE
528 /*
529 * If process is being ktraced, turn off - unless
530 * root set it.
531 */
532 if (p->p_tracep && !(p->p_traceflag & KTRFAC_ROOT)) {
fa4905b1 533 struct vnode *tvp = p->p_tracep;
1c79356b
A
534 p->p_tracep = NULL;
535 p->p_traceflag = 0;
fa4905b1 536 vrele(tvp);
1c79356b
A
537 }
538#endif
539 if (origvattr.va_mode & VSUID)
540 p->p_ucred->cr_uid = origvattr.va_uid;
541 if (origvattr.va_mode & VSGID)
542 p->p_ucred->cr_gid = origvattr.va_gid;
543
544 set_security_token(p);
545 p->p_flag |= P_SUGID;
546
547 /* Radar 2261856; setuid security hole fix */
548 /* Patch from OpenBSD: A. Ramesh */
549 /*
550 * XXX For setuid processes, attempt to ensure that
551 * stdin, stdout, and stderr are already allocated.
552 * We do not want userland to accidentally allocate
553 * descriptors in this range which has implied meaning
554 * to libc.
555 */
556 for (i = 0; i < 3; i++) {
557 extern struct fileops vnops;
558 struct nameidata nd1;
559 struct file *fp;
560 int indx;
561
562 if (p->p_fd->fd_ofiles[i] == NULL) {
563 if ((error = falloc(p, &fp, &indx)) != 0)
564 continue;
565 NDINIT(&nd1, LOOKUP, FOLLOW, UIO_SYSSPACE,
566 "/dev/null", p);
567 if ((error = vn_open(&nd1, FREAD, 0)) != 0) {
568 ffree(fp);
569 p->p_fd->fd_ofiles[indx] = NULL;
570 break;
571 }
572 fp->f_flag = FREAD;
573 fp->f_type = DTYPE_VNODE;
574 fp->f_ops = &vnops;
575 fp->f_data = (caddr_t)nd1.ni_vp;
576 VOP_UNLOCK(nd1.ni_vp, 0, p);
577 }
578 }
579 }
580 p->p_cred->p_svuid = p->p_ucred->cr_uid;
581 p->p_cred->p_svgid = p->p_ucred->cr_gid;
582
0b4e3aa0 583 if (!vfexec && (p->p_flag & P_TRACED)) {
1c79356b 584 psignal(p, SIGTRAP);
1c79356b 585 ast_on(AST_BSD);
1c79356b
A
586 }
587
588 if (error) {
0b4e3aa0 589 goto badtoolate;
1c79356b
A
590 }
591 VOP_LOCK(vp, LK_EXCLUSIVE | LK_RETRY, p);
592 vput(vp);
593 vp = NULL;
594
595 if (load_result.unixproc &&
0b4e3aa0
A
596 create_unix_stack(get_task_map(task),
597 load_result.user_stack, load_result.customstack, p)) {
1c79356b 598 error = load_return_to_errno(LOAD_NOSPACE);
0b4e3aa0
A
599 goto badtoolate;
600 }
601
602 if (vfexec) {
603 uthread->uu_ar0 = (void *)get_user_regs(thr_act);
1c79356b
A
604 }
605
606 /*
607 * Copy back arglist if necessary.
608 */
609
0b4e3aa0 610
1c79356b 611 ucp = p->user_stack;
0b4e3aa0
A
612 if (vfexec) {
613 old_map = vm_map_switch(get_task_map(task));
614 }
1c79356b
A
615 if (load_result.unixproc) {
616 int pathptr;
617
618 ucp = ucp - nc - NBPW; /* begining of the STRING AREA */
619
620 /*
621 * Support for new app package launching for Mac OS X allocates
622 * the "path" at the begining of the execargs buffer.
623 * copy it just before the string area.
624 */
0b4e3aa0 625 savedpathlen = (savedpathlen + NBPW-1) & ~(NBPW-1);
1c79356b
A
626 len = 0;
627 pathptr = ucp - savedpathlen;
628 error = copyoutstr(savedpath, (caddr_t)pathptr,
629 (unsigned)savedpathlen, &len);
0b4e3aa0
A
630 if (error) {
631 if (vfexec)
632 vm_map_switch(old_map);
633 goto badtoolate;
634 }
1c79356b
A
635
636 /* Save a NULL pointer below it */
637 (void) suword((caddr_t)(pathptr - NBPW), 0);
638
639 /* Save the pointer to "path" just below it */
640 (void) suword((caddr_t)(pathptr - 2*NBPW), pathptr);
641
642 /*
643 * na includes arg[] and env[].
644 * NBPW for 2 NULL one each ofter arg[argc -1] and env[n]
645 * NBPW for argc
646 * skip over saved path, NBPW for pointer to path,
647 * and NBPW for the NULL after pointer to path.
648 */
649 ap = ucp - na*NBPW - 3*NBPW - savedpathlen - 2*NBPW;
650 uthread->uu_ar0[SP] = ap;
651 (void) suword((caddr_t)ap, na-ne); /* argc */
652 nc = 0;
653 cc = 0;
654
655 cp = (char *) execargsp;
656 cc = NCARGS - savedpathlen - 2*NBPW;
657 ps.ps_argvstr = (char *)ucp; /* first argv string */
658 ps.ps_nargvstr = na - ne; /* argc */
659 for (;;) {
660 ap += NBPW;
661 if (na == ne) {
662 (void) suword((caddr_t)ap, 0);
663 ap += NBPW;
664 ps.ps_envstr = (char *)ucp;
665 ps.ps_nenvstr = ne;
666 }
667 if (--na < 0)
668 break;
669 (void) suword((caddr_t)ap, ucp);
670 do {
671 error = copyoutstr(cp, (caddr_t)ucp,
672 (unsigned)cc, &len);
673 ucp += len;
674 cp += len;
675 nc += len;
676 cc -= len;
677 } while (error == ENAMETOOLONG);
678 if (error == EFAULT)
679 break; /* bad stack - user's problem */
680 }
681 (void) suword((caddr_t)ap, 0);
682 }
683
684 if (load_result.dynlinker) {
685 ap = uthread->uu_ar0[SP] -= 4;
686 (void) suword((caddr_t)ap, load_result.mach_header);
687 }
688
0b4e3aa0
A
689 if (vfexec) {
690 vm_map_switch(old_map);
691 }
1c79356b
A
692#if defined(i386) || defined(ppc)
693 uthread->uu_ar0[PC] = load_result.entry_point;
694#else
695#error architecture not implemented!
696#endif
697
698 /* Stop profiling */
699 stopprofclock(p);
700
701 /*
702 * Reset signal state.
703 */
704 execsigs(p);
705
706 /*
707 * Close file descriptors
708 * which specify close-on-exec.
709 */
710 fdexec(p);
711 /* FIXME: Till vmspace inherit is fixed: */
712 if (p->vm_shm)
713 shmexit(p);
714
715 /*
716 * Remember file name for accounting.
717 */
718 p->p_acflag &= ~AFORK;
719 if (nd.ni_cnd.cn_namelen > MAXCOMLEN)
720 nd.ni_cnd.cn_namelen = MAXCOMLEN;
721 bcopy((caddr_t)nd.ni_cnd.cn_nameptr, (caddr_t)p->p_comm,
722 (unsigned)nd.ni_cnd.cn_namelen);
723 p->p_comm[nd.ni_cnd.cn_namelen] = '\0';
724
725 {
726 /* This is for kdebug */
727 long dbg_arg1, dbg_arg2, dbg_arg3, dbg_arg4;
728
729 /* Collect the pathname for tracing */
730 kdbg_trace_string(p, &dbg_arg1, &dbg_arg2, &dbg_arg3, &dbg_arg4);
0b4e3aa0
A
731
732 if (vfexec)
733 KERNEL_DEBUG_CONSTANT1((TRACEDBG_CODE(DBG_TRACE_STRING, 2)) | DBG_FUNC_NONE,
734 dbg_arg1, dbg_arg2, dbg_arg3, dbg_arg4, getshuttle_thread(thr_act));
735 else
736 KERNEL_DEBUG_CONSTANT((TRACEDBG_CODE(DBG_TRACE_STRING, 2)) | DBG_FUNC_NONE,
737 dbg_arg1, dbg_arg2, dbg_arg3, dbg_arg4, 0);
1c79356b
A
738 }
739
740 /*
741 * mark as execed, wakeup the process that vforked (if any) and tell
742 * it that it now has it's own resources back
743 */
744 p->p_flag |= P_EXEC;
745 if (p->p_pptr && (p->p_flag & P_PPWAIT)) {
746 p->p_flag &= ~P_PPWAIT;
747 wakeup((caddr_t)p->p_pptr);
748 }
749
0b4e3aa0
A
750 if (vfexec && (p->p_flag & P_TRACED)) {
751 psignal_vfork(p, new_task, thr_act, SIGTRAP);
752 }
753
754badtoolate:
755 if (vfexec) {
756 (void) thread_resume(thr_act);
757 task_deallocate(new_task);
758 act_deallocate(thr_act);
759 if (error)
760 error = 0;
761 }
1c79356b
A
762bad:
763 FREE_ZONE(nd.ni_cnd.cn_pnbuf, nd.ni_cnd.cn_pnlen, M_NAMEI);
764 if (vp)
765 vput(vp);
766bad1:
1c79356b 767 if (execargs)
765c9de3 768 execargs_free(execargs);
0b4e3aa0
A
769 if (!error && vfexec) {
770 vfork_return(current_act(), p->p_pptr, p, retval);
771 return(0);
772 }
1c79356b
A
773 return(error);
774}
775
776
777#define unix_stack_size(p) (p->p_rlimit[RLIMIT_STACK].rlim_cur)
778
779kern_return_t
0b4e3aa0 780create_unix_stack(map, user_stack, customstack, p)
1c79356b
A
781 vm_map_t map;
782 vm_offset_t user_stack;
0b4e3aa0 783 int customstack;
1c79356b
A
784 struct proc *p;
785{
786 vm_size_t size;
787 vm_offset_t addr;
788
789 p->user_stack = user_stack;
0b4e3aa0
A
790 if (!customstack) {
791 size = round_page(unix_stack_size(p));
792 addr = trunc_page(user_stack - size);
793 return (vm_allocate(map,&addr, size, FALSE));
794 } else
795 return(KERN_SUCCESS);
1c79356b
A
796}
797
798#include <sys/reboot.h>
799
800char init_program_name[128] = "/sbin/mach_init\0";
801
802char init_args[128] = "";
803
804struct execve_args init_exec_args;
805int init_attempts = 0;
806
807
808void
809load_init_program(p)
810 struct proc *p;
811{
812 vm_offset_t init_addr;
813 int *old_ap;
814 char *argv[3];
815 int error;
816 register_t retval[2];
817 struct uthread * ut;
818
819 unix_master();
820
821 error = 0;
822
823 /* init_args are copied in string form directly from bootstrap */
824
825 do {
826 if (boothowto & RB_INITNAME) {
827 printf("init program? ");
828#if FIXME /* [ */
829 gets(init_program_name, init_program_name);
830#endif /* FIXME ] */
831 }
832
833 if (error && ((boothowto & RB_INITNAME) == 0) &&
834 (init_attempts == 1)) {
835 static char other_init[] = "/etc/mach_init";
836 printf("Load of %s, errno %d, trying %s\n",
837 init_program_name, error, other_init);
838 error = 0;
839 bcopy(other_init, init_program_name,
840 sizeof(other_init));
841 }
842
843 init_attempts++;
844
845 if (error) {
846 printf("Load of %s failed, errno %d\n",
847 init_program_name, error);
848 error = 0;
849 boothowto |= RB_INITNAME;
850 continue;
851 }
852
853 /*
854 * Copy out program name.
855 */
856
857 init_addr = VM_MIN_ADDRESS;
858 (void) vm_allocate(current_map(), &init_addr,
859 PAGE_SIZE, TRUE);
860 if (init_addr == 0)
861 init_addr++;
862 (void) copyout((caddr_t) init_program_name,
863 (caddr_t) (init_addr),
864 (unsigned) sizeof(init_program_name)+1);
865
866 argv[0] = (char *) init_addr;
867 init_addr += sizeof(init_program_name);
868 init_addr = (vm_offset_t)ROUND_PTR(char, init_addr);
869
870 /*
871 * Put out first (and only) argument, similarly.
872 * Assumes everything fits in a page as allocated
873 * above.
874 */
875
876 (void) copyout((caddr_t) init_args,
877 (caddr_t) (init_addr),
878 (unsigned) sizeof(init_args));
879
880 argv[1] = (char *) init_addr;
881 init_addr += sizeof(init_args);
882 init_addr = (vm_offset_t)ROUND_PTR(char, init_addr);
883
884 /*
885 * Null-end the argument list
886 */
887
888 argv[2] = (char *) 0;
889
890 /*
891 * Copy out the argument list.
892 */
893
894 (void) copyout((caddr_t) argv,
895 (caddr_t) (init_addr),
896 (unsigned) sizeof(argv));
897
898 /*
899 * Set up argument block for fake call to execve.
900 */
901
902 init_exec_args.fname = argv[0];
903 init_exec_args.argp = (char **) init_addr;
904 init_exec_args.envp = 0;
905
906 /* So that mach_init task
907 * is set with uid,gid 0 token
908 */
909 set_security_token(p);
910
911 error = execve(p,&init_exec_args,retval);
912 } while (error);
913
914 unix_release();
915}
916
917/*
918 * Convert a load_return_t to an errno.
919 */
920static int
921load_return_to_errno(load_return_t lrtn)
922{
923 switch (lrtn) {
924 case LOAD_SUCCESS:
925 return 0;
926 case LOAD_BADARCH:
927 return EBADARCH;
928 case LOAD_BADMACHO:
929 return EBADMACHO;
930 case LOAD_SHLIB:
931 return ESHLIBVERS;
932 case LOAD_NOSPACE:
933 return ENOMEM;
934 case LOAD_PROTECT:
935 return EACCES;
936 case LOAD_RESOURCE:
937 case LOAD_FAILURE:
938 default:
939 return EBADEXEC;
940 }
941}
942
943/*
944 * exec_check_access()
945 */
946int
947check_exec_access(p, vp, vap)
948 struct proc *p;
949 struct vnode *vp;
950 struct vattr *vap;
951{
952 int flag;
953 int error;
954
955 if (error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p))
956 return (error);
957 flag = p->p_flag;
958 if (flag & P_TRACED) {
959 if (error = VOP_ACCESS(vp, VREAD, p->p_ucred, p))
960 return (error);
961 }
962 if (vp->v_type != VREG ||
963 (vap->va_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) == 0)
964 return (EACCES);
965 return (0);
966}
967
765c9de3
A
968#include <mach/mach_types.h>
969#include <mach/vm_prot.h>
970#include <mach/semaphore.h>
971#include <mach/sync_policy.h>
972#include <kern/clock.h>
973#include <mach/kern_return.h>
974
975extern semaphore_t execve_semaphore;
976
977static int
978execargs_alloc(addrp)
979 vm_offset_t *addrp;
980{
981 kern_return_t kret;
982
983 kret = semaphore_wait(execve_semaphore);
984 if (kret != KERN_SUCCESS)
985 switch (kret) {
986 default:
987 return (EINVAL);
988 case KERN_INVALID_ADDRESS:
989 case KERN_PROTECTION_FAILURE:
990 return (EACCES);
991 case KERN_ABORTED:
992 case KERN_OPERATION_TIMED_OUT:
993 return (EINTR);
994 }
995
996 kret = kmem_alloc_pageable(bsd_pageable_map, addrp, NCARGS);
997 if (kret != KERN_SUCCESS)
998 return (ENOMEM);
999
1000 return (0);
1001}
1002
1003static int
1004execargs_free(addr)
1005 vm_offset_t addr;
1006{
1007 kern_return_t kret;
1008
1009 kmem_free(bsd_pageable_map, addr, NCARGS);
1010
1011 kret = semaphore_signal(execve_semaphore);
1012 switch (kret) {
1013 case KERN_INVALID_ADDRESS:
1014 case KERN_PROTECTION_FAILURE:
1015 return (EINVAL);
1016 case KERN_ABORTED:
1017 case KERN_OPERATION_TIMED_OUT:
1018 return (EINTR);
1019 case KERN_SUCCESS:
1020 return(0);
1021 default:
1022 return (EINVAL);
1023 }
1024}
1025