]> git.saurik.com Git - apple/xnu.git/blob - bsd/kern/kern_exec.c
7dd27b97cbecc7d4c71917223286b8b601abda24
[apple/xnu.git] / bsd / kern / kern_exec.c
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
107 extern vm_map_t bsd_pageable_map;
108
109 #define ROUND_PTR(type, addr) \
110 (type *)( ( (unsigned)(addr) + 16 - 1) \
111 & ~(16 - 1) )
112
113 static int load_return_to_errno(load_return_t lrtn);
114 int execve(struct proc *p, struct execve_args *uap, register_t *retval);
115 static int execargs_alloc(vm_offset_t *addrp);
116 static int execargs_free(vm_offset_t addr);
117
118 int
119 execv(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 */
129 int
130 execve(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;
160 vm_map_t old_map;
161 vm_map_t map;
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;
177 task_t task;
178 task_t new_task;
179 thread_act_t thr_act;
180 int numthreads;
181 int vfexec=0;
182 unsigned long arch_offset =0;
183 unsigned long arch_size = 0;
184
185 task = current_task();
186 thr_act = current_act();
187 uthread = get_bsdthread_info(thr_act);
188
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 }
199 }
200 }
201
202 error = execargs_alloc(&execargs);
203 if (error)
204 return(error);
205
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
255 again:
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
474 arch_offset = fat_arch.offset;
475 arch_size = fat_arch.size;
476 } else {
477 /*
478 * Load the Mach-O file.
479 */
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
501 }
502
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
510 if (lret != LOAD_SUCCESS) {
511 error = load_return_to_errno(lret);
512 goto badtoolate;
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)) {
533 vrele(p->p_tracep);
534 p->p_tracep = NULL;
535 p->p_traceflag = 0;
536 }
537 #endif
538 if (origvattr.va_mode & VSUID)
539 p->p_ucred->cr_uid = origvattr.va_uid;
540 if (origvattr.va_mode & VSGID)
541 p->p_ucred->cr_gid = origvattr.va_gid;
542
543 set_security_token(p);
544 p->p_flag |= P_SUGID;
545
546 /* Radar 2261856; setuid security hole fix */
547 /* Patch from OpenBSD: A. Ramesh */
548 /*
549 * XXX For setuid processes, attempt to ensure that
550 * stdin, stdout, and stderr are already allocated.
551 * We do not want userland to accidentally allocate
552 * descriptors in this range which has implied meaning
553 * to libc.
554 */
555 for (i = 0; i < 3; i++) {
556 extern struct fileops vnops;
557 struct nameidata nd1;
558 struct file *fp;
559 int indx;
560
561 if (p->p_fd->fd_ofiles[i] == NULL) {
562 if ((error = falloc(p, &fp, &indx)) != 0)
563 continue;
564 NDINIT(&nd1, LOOKUP, FOLLOW, UIO_SYSSPACE,
565 "/dev/null", p);
566 if ((error = vn_open(&nd1, FREAD, 0)) != 0) {
567 ffree(fp);
568 p->p_fd->fd_ofiles[indx] = NULL;
569 break;
570 }
571 fp->f_flag = FREAD;
572 fp->f_type = DTYPE_VNODE;
573 fp->f_ops = &vnops;
574 fp->f_data = (caddr_t)nd1.ni_vp;
575 VOP_UNLOCK(nd1.ni_vp, 0, p);
576 }
577 }
578 }
579 p->p_cred->p_svuid = p->p_ucred->cr_uid;
580 p->p_cred->p_svgid = p->p_ucred->cr_gid;
581
582 if (!vfexec && (p->p_flag & P_TRACED)) {
583 psignal(p, SIGTRAP);
584 ast_on(AST_BSD);
585 }
586
587 if (error) {
588 goto badtoolate;
589 }
590 VOP_LOCK(vp, LK_EXCLUSIVE | LK_RETRY, p);
591 vput(vp);
592 vp = NULL;
593
594 if (load_result.unixproc &&
595 create_unix_stack(get_task_map(task),
596 load_result.user_stack, load_result.customstack, p)) {
597 error = load_return_to_errno(LOAD_NOSPACE);
598 goto badtoolate;
599 }
600
601 if (vfexec) {
602 uthread->uu_ar0 = (void *)get_user_regs(thr_act);
603 }
604
605 /*
606 * Copy back arglist if necessary.
607 */
608
609
610 ucp = p->user_stack;
611 if (vfexec) {
612 old_map = vm_map_switch(get_task_map(task));
613 }
614 if (load_result.unixproc) {
615 int pathptr;
616
617 ucp = ucp - nc - NBPW; /* begining of the STRING AREA */
618
619 /*
620 * Support for new app package launching for Mac OS X allocates
621 * the "path" at the begining of the execargs buffer.
622 * copy it just before the string area.
623 */
624 savedpathlen = (savedpathlen + NBPW-1) & ~(NBPW-1);
625 len = 0;
626 pathptr = ucp - savedpathlen;
627 error = copyoutstr(savedpath, (caddr_t)pathptr,
628 (unsigned)savedpathlen, &len);
629 if (error) {
630 if (vfexec)
631 vm_map_switch(old_map);
632 goto badtoolate;
633 }
634
635 /* Save a NULL pointer below it */
636 (void) suword((caddr_t)(pathptr - NBPW), 0);
637
638 /* Save the pointer to "path" just below it */
639 (void) suword((caddr_t)(pathptr - 2*NBPW), pathptr);
640
641 /*
642 * na includes arg[] and env[].
643 * NBPW for 2 NULL one each ofter arg[argc -1] and env[n]
644 * NBPW for argc
645 * skip over saved path, NBPW for pointer to path,
646 * and NBPW for the NULL after pointer to path.
647 */
648 ap = ucp - na*NBPW - 3*NBPW - savedpathlen - 2*NBPW;
649 uthread->uu_ar0[SP] = ap;
650 (void) suword((caddr_t)ap, na-ne); /* argc */
651 nc = 0;
652 cc = 0;
653
654 cp = (char *) execargsp;
655 cc = NCARGS - savedpathlen - 2*NBPW;
656 ps.ps_argvstr = (char *)ucp; /* first argv string */
657 ps.ps_nargvstr = na - ne; /* argc */
658 for (;;) {
659 ap += NBPW;
660 if (na == ne) {
661 (void) suword((caddr_t)ap, 0);
662 ap += NBPW;
663 ps.ps_envstr = (char *)ucp;
664 ps.ps_nenvstr = ne;
665 }
666 if (--na < 0)
667 break;
668 (void) suword((caddr_t)ap, ucp);
669 do {
670 error = copyoutstr(cp, (caddr_t)ucp,
671 (unsigned)cc, &len);
672 ucp += len;
673 cp += len;
674 nc += len;
675 cc -= len;
676 } while (error == ENAMETOOLONG);
677 if (error == EFAULT)
678 break; /* bad stack - user's problem */
679 }
680 (void) suword((caddr_t)ap, 0);
681 }
682
683 if (load_result.dynlinker) {
684 ap = uthread->uu_ar0[SP] -= 4;
685 (void) suword((caddr_t)ap, load_result.mach_header);
686 }
687
688 if (vfexec) {
689 vm_map_switch(old_map);
690 }
691 #if defined(i386) || defined(ppc)
692 uthread->uu_ar0[PC] = load_result.entry_point;
693 #else
694 #error architecture not implemented!
695 #endif
696
697 /* Stop profiling */
698 stopprofclock(p);
699
700 /*
701 * Reset signal state.
702 */
703 execsigs(p);
704
705 /*
706 * Close file descriptors
707 * which specify close-on-exec.
708 */
709 fdexec(p);
710 /* FIXME: Till vmspace inherit is fixed: */
711 if (p->vm_shm)
712 shmexit(p);
713
714 /*
715 * Remember file name for accounting.
716 */
717 p->p_acflag &= ~AFORK;
718 if (nd.ni_cnd.cn_namelen > MAXCOMLEN)
719 nd.ni_cnd.cn_namelen = MAXCOMLEN;
720 bcopy((caddr_t)nd.ni_cnd.cn_nameptr, (caddr_t)p->p_comm,
721 (unsigned)nd.ni_cnd.cn_namelen);
722 p->p_comm[nd.ni_cnd.cn_namelen] = '\0';
723
724 {
725 /* This is for kdebug */
726 long dbg_arg1, dbg_arg2, dbg_arg3, dbg_arg4;
727
728 /* Collect the pathname for tracing */
729 kdbg_trace_string(p, &dbg_arg1, &dbg_arg2, &dbg_arg3, &dbg_arg4);
730
731 if (vfexec)
732 KERNEL_DEBUG_CONSTANT1((TRACEDBG_CODE(DBG_TRACE_STRING, 2)) | DBG_FUNC_NONE,
733 dbg_arg1, dbg_arg2, dbg_arg3, dbg_arg4, getshuttle_thread(thr_act));
734 else
735 KERNEL_DEBUG_CONSTANT((TRACEDBG_CODE(DBG_TRACE_STRING, 2)) | DBG_FUNC_NONE,
736 dbg_arg1, dbg_arg2, dbg_arg3, dbg_arg4, 0);
737 }
738
739 /*
740 * mark as execed, wakeup the process that vforked (if any) and tell
741 * it that it now has it's own resources back
742 */
743 p->p_flag |= P_EXEC;
744 if (p->p_pptr && (p->p_flag & P_PPWAIT)) {
745 p->p_flag &= ~P_PPWAIT;
746 wakeup((caddr_t)p->p_pptr);
747 }
748
749 if (vfexec && (p->p_flag & P_TRACED)) {
750 psignal_vfork(p, new_task, thr_act, SIGTRAP);
751 }
752
753 badtoolate:
754 if (vfexec) {
755 (void) thread_resume(thr_act);
756 task_deallocate(new_task);
757 act_deallocate(thr_act);
758 if (error)
759 error = 0;
760 }
761 bad:
762 FREE_ZONE(nd.ni_cnd.cn_pnbuf, nd.ni_cnd.cn_pnlen, M_NAMEI);
763 if (vp)
764 vput(vp);
765 bad1:
766 if (execargs)
767 execargs_free(execargs);
768 if (!error && vfexec) {
769 vfork_return(current_act(), p->p_pptr, p, retval);
770 return(0);
771 }
772 return(error);
773 }
774
775
776 #define unix_stack_size(p) (p->p_rlimit[RLIMIT_STACK].rlim_cur)
777
778 kern_return_t
779 create_unix_stack(map, user_stack, customstack, p)
780 vm_map_t map;
781 vm_offset_t user_stack;
782 int customstack;
783 struct proc *p;
784 {
785 vm_size_t size;
786 vm_offset_t addr;
787
788 p->user_stack = user_stack;
789 if (!customstack) {
790 size = round_page(unix_stack_size(p));
791 addr = trunc_page(user_stack - size);
792 return (vm_allocate(map,&addr, size, FALSE));
793 } else
794 return(KERN_SUCCESS);
795 }
796
797 #include <sys/reboot.h>
798
799 char init_program_name[128] = "/sbin/mach_init\0";
800
801 char init_args[128] = "";
802
803 struct execve_args init_exec_args;
804 int init_attempts = 0;
805
806
807 void
808 load_init_program(p)
809 struct proc *p;
810 {
811 vm_offset_t init_addr;
812 int *old_ap;
813 char *argv[3];
814 int error;
815 register_t retval[2];
816 struct uthread * ut;
817
818 unix_master();
819
820 error = 0;
821
822 /* init_args are copied in string form directly from bootstrap */
823
824 do {
825 if (boothowto & RB_INITNAME) {
826 printf("init program? ");
827 #if FIXME /* [ */
828 gets(init_program_name, init_program_name);
829 #endif /* FIXME ] */
830 }
831
832 if (error && ((boothowto & RB_INITNAME) == 0) &&
833 (init_attempts == 1)) {
834 static char other_init[] = "/etc/mach_init";
835 printf("Load of %s, errno %d, trying %s\n",
836 init_program_name, error, other_init);
837 error = 0;
838 bcopy(other_init, init_program_name,
839 sizeof(other_init));
840 }
841
842 init_attempts++;
843
844 if (error) {
845 printf("Load of %s failed, errno %d\n",
846 init_program_name, error);
847 error = 0;
848 boothowto |= RB_INITNAME;
849 continue;
850 }
851
852 /*
853 * Copy out program name.
854 */
855
856 init_addr = VM_MIN_ADDRESS;
857 (void) vm_allocate(current_map(), &init_addr,
858 PAGE_SIZE, TRUE);
859 if (init_addr == 0)
860 init_addr++;
861 (void) copyout((caddr_t) init_program_name,
862 (caddr_t) (init_addr),
863 (unsigned) sizeof(init_program_name)+1);
864
865 argv[0] = (char *) init_addr;
866 init_addr += sizeof(init_program_name);
867 init_addr = (vm_offset_t)ROUND_PTR(char, init_addr);
868
869 /*
870 * Put out first (and only) argument, similarly.
871 * Assumes everything fits in a page as allocated
872 * above.
873 */
874
875 (void) copyout((caddr_t) init_args,
876 (caddr_t) (init_addr),
877 (unsigned) sizeof(init_args));
878
879 argv[1] = (char *) init_addr;
880 init_addr += sizeof(init_args);
881 init_addr = (vm_offset_t)ROUND_PTR(char, init_addr);
882
883 /*
884 * Null-end the argument list
885 */
886
887 argv[2] = (char *) 0;
888
889 /*
890 * Copy out the argument list.
891 */
892
893 (void) copyout((caddr_t) argv,
894 (caddr_t) (init_addr),
895 (unsigned) sizeof(argv));
896
897 /*
898 * Set up argument block for fake call to execve.
899 */
900
901 init_exec_args.fname = argv[0];
902 init_exec_args.argp = (char **) init_addr;
903 init_exec_args.envp = 0;
904
905 /* So that mach_init task
906 * is set with uid,gid 0 token
907 */
908 set_security_token(p);
909
910 error = execve(p,&init_exec_args,retval);
911 } while (error);
912
913 unix_release();
914 }
915
916 /*
917 * Convert a load_return_t to an errno.
918 */
919 static int
920 load_return_to_errno(load_return_t lrtn)
921 {
922 switch (lrtn) {
923 case LOAD_SUCCESS:
924 return 0;
925 case LOAD_BADARCH:
926 return EBADARCH;
927 case LOAD_BADMACHO:
928 return EBADMACHO;
929 case LOAD_SHLIB:
930 return ESHLIBVERS;
931 case LOAD_NOSPACE:
932 return ENOMEM;
933 case LOAD_PROTECT:
934 return EACCES;
935 case LOAD_RESOURCE:
936 case LOAD_FAILURE:
937 default:
938 return EBADEXEC;
939 }
940 }
941
942 /*
943 * exec_check_access()
944 */
945 int
946 check_exec_access(p, vp, vap)
947 struct proc *p;
948 struct vnode *vp;
949 struct vattr *vap;
950 {
951 int flag;
952 int error;
953
954 if (error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p))
955 return (error);
956 flag = p->p_flag;
957 if (flag & P_TRACED) {
958 if (error = VOP_ACCESS(vp, VREAD, p->p_ucred, p))
959 return (error);
960 }
961 if (vp->v_type != VREG ||
962 (vap->va_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) == 0)
963 return (EACCES);
964 return (0);
965 }
966
967 #include <mach/mach_types.h>
968 #include <mach/vm_prot.h>
969 #include <mach/semaphore.h>
970 #include <mach/sync_policy.h>
971 #include <kern/clock.h>
972 #include <mach/kern_return.h>
973
974 extern semaphore_t execve_semaphore;
975
976 static int
977 execargs_alloc(addrp)
978 vm_offset_t *addrp;
979 {
980 kern_return_t kret;
981
982 kret = semaphore_wait(execve_semaphore);
983 if (kret != KERN_SUCCESS)
984 switch (kret) {
985 default:
986 return (EINVAL);
987 case KERN_INVALID_ADDRESS:
988 case KERN_PROTECTION_FAILURE:
989 return (EACCES);
990 case KERN_ABORTED:
991 case KERN_OPERATION_TIMED_OUT:
992 return (EINTR);
993 }
994
995 kret = kmem_alloc_pageable(bsd_pageable_map, addrp, NCARGS);
996 if (kret != KERN_SUCCESS)
997 return (ENOMEM);
998
999 return (0);
1000 }
1001
1002 static int
1003 execargs_free(addr)
1004 vm_offset_t addr;
1005 {
1006 kern_return_t kret;
1007
1008 kmem_free(bsd_pageable_map, addr, NCARGS);
1009
1010 kret = semaphore_signal(execve_semaphore);
1011 switch (kret) {
1012 case KERN_INVALID_ADDRESS:
1013 case KERN_PROTECTION_FAILURE:
1014 return (EINVAL);
1015 case KERN_ABORTED:
1016 case KERN_OPERATION_TIMED_OUT:
1017 return (EINTR);
1018 case KERN_SUCCESS:
1019 return(0);
1020 default:
1021 return (EINVAL);
1022 }
1023 }
1024