Commit | Line | Data |
---|---|---|
1c79356b | 1 | /* |
e5568f75 | 2 | * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved. |
1c79356b A |
3 | * |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
e5568f75 A |
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. | |
1c79356b | 11 | * |
e5568f75 A |
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 | |
1c79356b A |
14 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
15 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
e5568f75 A |
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. | |
1c79356b A |
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> | |
55e303ae | 92 | #include <sys/aio_kern.h> |
1c79356b | 93 | |
e5568f75 A |
94 | #include <bsm/audit_kernel.h> |
95 | ||
1c79356b A |
96 | #include <mach/vm_param.h> |
97 | ||
98 | #include <vm/vm_map.h> | |
55e303ae A |
99 | |
100 | extern vm_map_t vm_map_switch(vm_map_t map); /* XXX */ | |
101 | ||
1c79356b | 102 | #include <vm/vm_kern.h> |
9bccf70c | 103 | #include <vm/vm_shared_memory_server.h> |
1c79356b A |
104 | |
105 | #include <kern/thread.h> | |
106 | #include <kern/task.h> | |
107 | ||
108 | #include <kern/ast.h> | |
109 | #include <kern/mach_loader.h> | |
110 | #include <mach-o/fat.h> | |
111 | #include <mach-o/loader.h> | |
112 | #include <machine/vmparam.h> | |
9bccf70c A |
113 | #if KTRACE |
114 | #include <sys/ktrace.h> | |
e5568f75 | 115 | #include <sys/ubc.h> |
9bccf70c A |
116 | #endif |
117 | ||
118 | int app_profile = 0; | |
1c79356b A |
119 | |
120 | extern vm_map_t bsd_pageable_map; | |
121 | ||
122 | #define ROUND_PTR(type, addr) \ | |
123 | (type *)( ( (unsigned)(addr) + 16 - 1) \ | |
124 | & ~(16 - 1) ) | |
125 | ||
126 | static int load_return_to_errno(load_return_t lrtn); | |
127 | int execve(struct proc *p, struct execve_args *uap, register_t *retval); | |
765c9de3 A |
128 | static int execargs_alloc(vm_offset_t *addrp); |
129 | static int execargs_free(vm_offset_t addr); | |
1c79356b A |
130 | |
131 | int | |
132 | execv(p, args, retval) | |
133 | struct proc *p; | |
134 | void *args; | |
135 | int *retval; | |
136 | { | |
137 | ((struct execve_args *)args)->envp = NULL; | |
138 | return (execve(p, args, retval)); | |
139 | } | |
140 | ||
55e303ae A |
141 | extern char classichandler[32]; |
142 | extern long classichandler_fsid; | |
143 | extern long classichandler_fileid; | |
144 | ||
145 | /* | |
146 | * Helper routine to get rid of a loop in execve. Given a pointer to | |
147 | * something for the arg list (which might be in kernel space or in user | |
148 | * space), copy it into the kernel buffer at the currentWritePt. This code | |
149 | * does the proper thing to get the data transferred. | |
150 | * bytesWritten, currentWritePt, and bytesLeft are kept up-to-date. | |
151 | */ | |
152 | ||
153 | static int copyArgument(char *argument, int pointerInKernel, | |
154 | int *bytesWritten,char **currentWritePt, | |
155 | int *bytesLeft){ | |
156 | int error = 0; | |
157 | do { | |
158 | size_t len = 0; | |
159 | if (*bytesLeft <= 0) { | |
160 | error = E2BIG; | |
161 | break; | |
162 | } | |
163 | if (pointerInKernel == UIO_SYSSPACE) { | |
164 | error = copystr(argument, *currentWritePt, (unsigned)*bytesLeft, &len); | |
165 | } else { | |
166 | /* | |
167 | * pointer in kernel == UIO_USERSPACE | |
168 | * Copy in from user space. | |
169 | */ | |
170 | error = copyinstr((caddr_t)argument, *currentWritePt, (unsigned)*bytesLeft, | |
171 | &len); | |
172 | } | |
173 | *currentWritePt += len; | |
174 | *bytesWritten += len; | |
175 | *bytesLeft -= len; | |
176 | } while (error == ENAMETOOLONG); | |
177 | return error; | |
178 | } | |
179 | ||
1c79356b A |
180 | /* ARGSUSED */ |
181 | int | |
182 | execve(p, uap, retval) | |
183 | register struct proc *p; | |
184 | register struct execve_args *uap; | |
185 | register_t *retval; | |
186 | { | |
187 | register struct ucred *cred = p->p_ucred; | |
188 | register struct filedesc *fdp = p->p_fd; | |
55e303ae A |
189 | int nc; |
190 | char *cp; | |
1c79356b A |
191 | int na, ne, ucp, ap, cc; |
192 | unsigned len; | |
55e303ae A |
193 | int executingInterpreter=0; |
194 | ||
195 | int executingClassic=0; | |
196 | char binaryWithClassicName[sizeof(p->p_comm)] = {0}; | |
1c79356b A |
197 | char *execnamep; |
198 | struct vnode *vp; | |
199 | struct vattr vattr; | |
200 | struct vattr origvattr; | |
201 | vm_offset_t execargs; | |
202 | struct nameidata nd; | |
203 | struct ps_strings ps; | |
204 | #define SHSIZE 512 | |
55e303ae A |
205 | /* Argument(s) to an interpreter. If we're executing a shell |
206 | * script, the name (#!/bin/csh) is allowed to be followed by | |
207 | * arguments. cfarg holds these arguments. | |
208 | */ | |
1c79356b A |
209 | char cfarg[SHSIZE]; |
210 | boolean_t is_fat; | |
211 | kern_return_t ret; | |
212 | struct mach_header *mach_header; | |
213 | struct fat_header *fat_header; | |
214 | struct fat_arch fat_arch; | |
215 | load_return_t lret; | |
216 | load_result_t load_result; | |
217 | struct uthread *uthread; | |
0b4e3aa0 A |
218 | vm_map_t old_map; |
219 | vm_map_t map; | |
1c79356b | 220 | int i; |
55e303ae A |
221 | boolean_t clean_regions = FALSE; |
222 | shared_region_mapping_t shared_region = NULL; | |
223 | shared_region_mapping_t initial_region = NULL; | |
224 | ||
1c79356b A |
225 | union { |
226 | /* #! and name of interpreter */ | |
227 | char ex_shell[SHSIZE]; | |
228 | /* Mach-O executable */ | |
229 | struct mach_header mach_header; | |
230 | /* Fat executable */ | |
231 | struct fat_header fat_header; | |
232 | char pad[512]; | |
233 | } exdata; | |
234 | int resid, error; | |
235 | char *savedpath; | |
236 | int savedpathlen = 0; | |
237 | vm_offset_t *execargsp; | |
238 | char *cpnospace; | |
0b4e3aa0 A |
239 | task_t task; |
240 | task_t new_task; | |
241 | thread_act_t thr_act; | |
1c79356b | 242 | int numthreads; |
0b4e3aa0 A |
243 | int vfexec=0; |
244 | unsigned long arch_offset =0; | |
245 | unsigned long arch_size = 0; | |
9bccf70c | 246 | char *ws_cache_name = NULL; /* used for pre-heat */ |
1c79356b | 247 | |
55e303ae A |
248 | /* |
249 | * XXXAUDIT: Currently, we only audit the pathname of the binary. | |
250 | * There may also be poor interaction with dyld. | |
251 | */ | |
252 | ||
253 | cfarg[0] = '\0'; /* initialize to null value. */ | |
0b4e3aa0 A |
254 | task = current_task(); |
255 | thr_act = current_act(); | |
256 | uthread = get_bsdthread_info(thr_act); | |
1c79356b | 257 | |
0b4e3aa0 A |
258 | if (uthread->uu_flag & P_VFORK) { |
259 | vfexec = 1; /* Mark in exec */ | |
260 | } else { | |
261 | if (task != kernel_task) { | |
262 | numthreads = get_task_numacts(task); | |
263 | if (numthreads <= 0 ) | |
264 | return(EINVAL); | |
265 | if (numthreads > 1) { | |
266 | return(EOPNOTSUPP); | |
267 | } | |
1c79356b A |
268 | } |
269 | } | |
270 | ||
765c9de3 A |
271 | error = execargs_alloc(&execargs); |
272 | if (error) | |
273 | return(error); | |
1c79356b | 274 | |
55e303ae | 275 | savedpath = (char *)execargs; |
1c79356b A |
276 | |
277 | /* | |
278 | * To support new app package launching for Mac OS X, the dyld | |
279 | * needs the first argument to execve() stored on the user stack. | |
280 | * Copyin the "path" at the begining of the "execargs" buffer | |
281 | * allocated above. | |
282 | * | |
283 | * We have to do this before namei() because in case of | |
284 | * symbolic links, namei() would overwrite the original "path". | |
285 | * In case the last symbolic link resolved was a relative pathname | |
9bccf70c | 286 | * we would lose the original "path", which could be an |
1c79356b A |
287 | * absolute pathname. This might be unacceptable for dyld. |
288 | */ | |
289 | /* XXX We could optimize to avoid copyinstr in the namei() */ | |
55e303ae A |
290 | |
291 | /* | |
292 | * XXXAUDIT: Note: the double copyin introduces an audit | |
293 | * race. To correct this race, we must use a single | |
294 | * copyin(). | |
295 | */ | |
1c79356b | 296 | |
55e303ae A |
297 | error = copyinstr(uap->fname, savedpath, |
298 | MAXPATHLEN, (size_t *)&savedpathlen); | |
299 | if (error) { | |
300 | execargs_free(execargs); | |
301 | return(error); | |
302 | } | |
1c79356b A |
303 | /* |
304 | * copyinstr will put in savedpathlen, the count of | |
305 | * characters (including NULL) in the path. | |
55e303ae | 306 | * No app profiles under chroot |
1c79356b | 307 | */ |
9bccf70c | 308 | |
55e303ae | 309 | if((fdp->fd_rdir == NULLVP) && (app_profile != 0)) { |
9bccf70c A |
310 | |
311 | /* grab the name of the file out of its path */ | |
312 | /* we will need this for lookup within the */ | |
313 | /* name file */ | |
314 | ws_cache_name = savedpath + savedpathlen; | |
315 | while (ws_cache_name[0] != '/') { | |
316 | if(ws_cache_name == savedpath) { | |
317 | ws_cache_name--; | |
318 | break; | |
319 | } | |
320 | ws_cache_name--; | |
321 | } | |
322 | ws_cache_name++; | |
323 | } | |
55e303ae | 324 | |
1c79356b A |
325 | /* Save the name aside for future use */ |
326 | execargsp = (vm_offset_t *)((char *)(execargs) + savedpathlen); | |
327 | ||
55e303ae | 328 | NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | SAVENAME | AUDITVNPATH1, |
1c79356b | 329 | UIO_USERSPACE, uap->fname, p); |
55e303ae A |
330 | error = namei(&nd); |
331 | if (error) | |
1c79356b A |
332 | goto bad1; |
333 | vp = nd.ni_vp; | |
334 | VOP_LEASE(vp, p, p->p_ucred, LEASE_READ); | |
335 | ||
336 | if ((error = VOP_GETATTR(vp, &origvattr, p->p_ucred, p))) | |
337 | goto bad; | |
338 | ||
339 | /* Check mount point */ | |
340 | if (vp->v_mount->mnt_flag & MNT_NOEXEC) { | |
341 | error = EACCES; | |
342 | goto bad; | |
343 | } | |
344 | ||
1c79356b A |
345 | if ((vp->v_mount->mnt_flag & MNT_NOSUID) || (p->p_flag & P_TRACED)) |
346 | origvattr.va_mode &= ~(VSUID | VSGID); | |
347 | ||
348 | *(&vattr) = *(&origvattr); | |
349 | ||
350 | again: | |
351 | error = check_exec_access(p, vp, &vattr); | |
352 | if (error) | |
353 | goto bad; | |
354 | ||
355 | /* | |
356 | * Read in first few bytes of file for segment sizes, magic number: | |
357 | * 407 = plain executable | |
358 | * 410 = RO text | |
359 | * 413 = demand paged RO text | |
360 | * Also an ASCII line beginning with #! is | |
361 | * the file name of a ``shell'' and arguments may be prepended | |
362 | * to the argument list if given here. | |
363 | * | |
364 | * SHELL NAMES ARE LIMITED IN LENGTH. | |
365 | * | |
366 | * ONLY ONE ARGUMENT MAY BE PASSED TO THE SHELL FROM | |
367 | * THE ASCII LINE. | |
368 | */ | |
369 | ||
370 | exdata.ex_shell[0] = '\0'; /* for zero length files */ | |
371 | ||
372 | error = vn_rdwr(UIO_READ, vp, (caddr_t)&exdata, sizeof (exdata), 0, | |
373 | UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid, p); | |
374 | ||
375 | if (error) | |
376 | goto bad; | |
377 | ||
378 | #ifndef lint | |
379 | if (resid > sizeof(exdata) - min(sizeof(exdata.mach_header), | |
380 | sizeof(exdata.fat_header)) | |
381 | && exdata.ex_shell[0] != '#') { | |
382 | error = ENOEXEC; | |
383 | goto bad; | |
384 | } | |
385 | #endif /* lint */ | |
386 | mach_header = &exdata.mach_header; | |
387 | fat_header = &exdata.fat_header; | |
55e303ae A |
388 | if ((mach_header->magic == MH_CIGAM) && |
389 | (classichandler[0] == 0)) { | |
390 | error = EBADARCH; | |
391 | goto bad; | |
392 | } else if ((mach_header->magic == MH_MAGIC) || | |
393 | (mach_header->magic == MH_CIGAM)) { | |
1c79356b | 394 | is_fat = FALSE; |
55e303ae A |
395 | } else if ((fat_header->magic == FAT_MAGIC) || |
396 | (fat_header->magic == FAT_CIGAM)) { | |
1c79356b | 397 | is_fat = TRUE; |
1c79356b | 398 | } else { |
55e303ae A |
399 | /* If we've already redirected once from an interpreted file |
400 | * to an interpreter, don't permit the second time. | |
401 | */ | |
1c79356b A |
402 | if (exdata.ex_shell[0] != '#' || |
403 | exdata.ex_shell[1] != '!' || | |
55e303ae | 404 | executingInterpreter) { |
1c79356b A |
405 | error = ENOEXEC; |
406 | goto bad; | |
407 | } | |
55e303ae A |
408 | if (executingClassic == 1) { |
409 | error = EBADARCH; | |
410 | goto bad; | |
411 | } | |
1c79356b A |
412 | cp = &exdata.ex_shell[2]; /* skip "#!" */ |
413 | while (cp < &exdata.ex_shell[SHSIZE]) { | |
55e303ae | 414 | if (*cp == '\t') /* convert all tabs to spaces */ |
1c79356b | 415 | *cp = ' '; |
55e303ae A |
416 | else if (*cp == '\n' || *cp == '#') { |
417 | *cp = '\0'; /* trunc the line at nl or comment */ | |
418 | ||
419 | /* go back and remove the spaces before the /n or # */ | |
420 | /* todo: do we have to do this if we fix the passing of args to shells ? */ | |
421 | if ( cp != &exdata.ex_shell[2] ) { | |
422 | do { | |
423 | if ( *(cp-1) != ' ') | |
424 | break; | |
425 | *(--cp) = '\0'; | |
426 | } while ( cp != &exdata.ex_shell[2] ); | |
427 | } | |
1c79356b A |
428 | break; |
429 | } | |
430 | cp++; | |
431 | } | |
432 | if (*cp != '\0') { | |
433 | error = ENOEXEC; | |
434 | goto bad; | |
435 | } | |
436 | cp = &exdata.ex_shell[2]; | |
437 | while (*cp == ' ') | |
438 | cp++; | |
439 | execnamep = cp; | |
440 | while (*cp && *cp != ' ') | |
441 | cp++; | |
442 | cfarg[0] = '\0'; | |
443 | cpnospace = cp; | |
444 | if (*cp) { | |
445 | *cp++ = '\0'; | |
446 | while (*cp == ' ') | |
447 | cp++; | |
448 | if (*cp) | |
449 | bcopy((caddr_t)cp, (caddr_t)cfarg, SHSIZE); | |
450 | } | |
451 | ||
452 | /* | |
453 | * Support for new app package launching for Mac OS X. | |
454 | * We are about to retry the execve() by changing the path to the | |
455 | * interpreter name. Need to re-initialize the savedpath and | |
456 | * savedpathlen. +1 for NULL. | |
457 | */ | |
458 | savedpathlen = (cpnospace - execnamep + 1); | |
55e303ae A |
459 | error = copystr(execnamep, savedpath, |
460 | savedpathlen, (size_t *)&savedpathlen); | |
1c79356b A |
461 | if (error) |
462 | goto bad; | |
463 | ||
464 | /* Save the name aside for future use */ | |
465 | execargsp = (vm_offset_t *)((char *)(execargs) + savedpathlen); | |
466 | ||
55e303ae | 467 | executingInterpreter= 1; |
1c79356b A |
468 | vput(vp); |
469 | nd.ni_cnd.cn_nameiop = LOOKUP; | |
470 | nd.ni_cnd.cn_flags = (nd.ni_cnd.cn_flags & HASBUF) | | |
471 | (FOLLOW | LOCKLEAF | SAVENAME); | |
472 | nd.ni_segflg = UIO_SYSSPACE; | |
473 | nd.ni_dirp = execnamep; | |
474 | if ((error = namei(&nd))) | |
475 | goto bad1; | |
476 | vp = nd.ni_vp; | |
477 | VOP_LEASE(vp, p, cred, LEASE_READ); | |
478 | if ((error = VOP_GETATTR(vp, &vattr, p->p_ucred, p))) | |
479 | goto bad; | |
480 | goto again; | |
481 | } | |
482 | ||
483 | /* | |
484 | * Collect arguments on "file" in swap space. | |
485 | */ | |
486 | na = 0; | |
487 | ne = 0; | |
488 | nc = 0; | |
489 | cc = 0; | |
490 | /* | |
491 | * Support for new app package launching for Mac OS X allocates | |
492 | * the "path" at the begining. | |
493 | * execargs get allocated after that | |
494 | */ | |
495 | cp = (char *) execargsp; /* running pointer for copy */ | |
496 | /* | |
497 | * size of execargs less sizeof "path", | |
498 | * a pointer to "path" and a NULL poiter | |
499 | */ | |
500 | cc = NCARGS - savedpathlen - 2*NBPW; | |
501 | /* | |
502 | * Copy arguments into file in argdev area. | |
503 | */ | |
55e303ae | 504 | |
1c79356b A |
505 | |
506 | /* | |
507 | * If we have a fat file, find "our" executable. | |
508 | */ | |
509 | if (is_fat) { | |
510 | /* | |
511 | * Look up our architecture in the fat file. | |
512 | */ | |
55e303ae A |
513 | lret = fatfile_getarch_affinity(vp,(vm_offset_t)fat_header, &fat_arch, |
514 | (p->p_flag & P_AFFINITY)); | |
1c79356b A |
515 | if (lret != LOAD_SUCCESS) { |
516 | error = load_return_to_errno(lret); | |
517 | goto bad; | |
518 | } | |
519 | /* Read the Mach-O header out of it */ | |
520 | error = vn_rdwr(UIO_READ, vp, (caddr_t)&exdata.mach_header, | |
521 | sizeof (exdata.mach_header), | |
522 | fat_arch.offset, | |
523 | UIO_SYSSPACE, (IO_UNIT|IO_NODELOCKED), cred, &resid, p); | |
524 | ||
525 | if (error) { | |
526 | goto bad; | |
527 | } | |
528 | ||
529 | /* Did we read a complete header? */ | |
530 | if (resid) { | |
531 | error = EBADEXEC; | |
532 | goto bad; | |
533 | } | |
534 | ||
535 | /* Is what we found a Mach-O executable */ | |
55e303ae A |
536 | if ((mach_header->magic != MH_MAGIC) && |
537 | (mach_header->magic != MH_CIGAM)) { | |
1c79356b A |
538 | error = ENOEXEC; |
539 | goto bad; | |
540 | } | |
541 | ||
0b4e3aa0 A |
542 | arch_offset = fat_arch.offset; |
543 | arch_size = fat_arch.size; | |
1c79356b A |
544 | } else { |
545 | /* | |
546 | * Load the Mach-O file. | |
547 | */ | |
0b4e3aa0 A |
548 | arch_offset = 0; |
549 | arch_size = (u_long)vattr.va_size; | |
550 | } | |
551 | ||
55e303ae A |
552 | if ( ! check_cpu_subtype(mach_header->cpusubtype) ) { |
553 | error = EBADARCH; | |
554 | goto bad; | |
555 | } | |
556 | ||
557 | if (mach_header->magic == MH_CIGAM) { | |
558 | ||
559 | int classicBinaryLen = nd.ni_cnd.cn_namelen; | |
560 | if (classicBinaryLen > MAXCOMLEN) | |
561 | classicBinaryLen = MAXCOMLEN; | |
562 | bcopy((caddr_t)nd.ni_cnd.cn_nameptr, | |
563 | (caddr_t)binaryWithClassicName, | |
564 | (unsigned)classicBinaryLen); | |
565 | binaryWithClassicName[classicBinaryLen] = '\0'; | |
566 | executingClassic = 1; | |
567 | ||
568 | vput(vp); /* cleanup? */ | |
569 | nd.ni_cnd.cn_nameiop = LOOKUP; | |
570 | ||
571 | nd.ni_cnd.cn_flags = (nd.ni_cnd.cn_flags & HASBUF) | | |
572 | /* (FOLLOW | LOCKLEAF | SAVENAME) */ | |
573 | (LOCKLEAF | SAVENAME); | |
574 | nd.ni_segflg = UIO_SYSSPACE; | |
575 | ||
576 | nd.ni_dirp = classichandler; | |
577 | if ((error = namei(&nd)) != 0) { | |
578 | error = EBADARCH; | |
579 | goto bad1; | |
580 | } | |
581 | vp = nd.ni_vp; | |
582 | ||
583 | VOP_LEASE(vp,p,cred,LEASE_READ); | |
584 | if ((error = VOP_GETATTR(vp,&vattr,p->p_ucred,p))) { | |
585 | goto bad; | |
586 | } | |
587 | goto again; | |
588 | } | |
589 | ||
590 | if (uap->argp != NULL) { | |
591 | /* geez -- why would argp ever be NULL, and why would we proceed? */ | |
592 | ||
593 | /* First, handle any argument massaging */ | |
594 | if (executingInterpreter && executingClassic) { | |
595 | error = copyArgument(classichandler,UIO_SYSSPACE,&nc,&cp,&cc); | |
596 | na++; | |
597 | if (error) goto bad; | |
598 | ||
599 | /* Now name the interpreter. */ | |
600 | error = copyArgument(savedpath,UIO_SYSSPACE,&nc,&cp,&cc); | |
601 | na++; | |
602 | if (error) goto bad; | |
603 | ||
604 | /* | |
605 | * if we're running an interpreter, as we'd be passing the | |
606 | * command line executable as an argument to the interpreter already. | |
607 | * Doing "execve("myShellScript","bogusName",arg1,arg2,...) | |
608 | * probably shouldn't ever let bogusName be seen by the shell | |
609 | * script. | |
610 | */ | |
611 | ||
612 | if (cfarg[0]) { | |
613 | error = copyArgument(cfarg,UIO_SYSSPACE,&nc,&cp,&cc); | |
614 | na++; | |
615 | if (error) goto bad; | |
616 | } | |
617 | ||
618 | char* originalExecutable = uap->fname; | |
619 | error = copyArgument(originalExecutable,UIO_USERSPACE,&nc,&cp,&cc); | |
620 | na++; | |
621 | /* remove argv[0] b/c we've already placed it at */ | |
622 | /* this point */ | |
623 | uap->argp++; | |
624 | if (error) goto bad; | |
625 | ||
626 | /* and continue with rest of the arguments. */ | |
627 | } else if (executingClassic) { | |
628 | error = copyArgument(classichandler,UIO_SYSSPACE,&nc,&cp,&cc); | |
629 | na++; | |
630 | if (error) goto bad; | |
631 | ||
632 | char* originalExecutable = uap->fname; | |
633 | error = copyArgument(originalExecutable,UIO_USERSPACE,&nc,&cp,&cc); | |
634 | if (error) goto bad; | |
635 | uap->argp++; | |
636 | na++; | |
637 | ||
638 | /* and rest of arguments continue as before. */ | |
639 | } else if (executingInterpreter) { | |
640 | char *actualExecutable = nd.ni_cnd.cn_nameptr; | |
641 | error = copyArgument(actualExecutable,UIO_SYSSPACE,&nc,&cp,&cc); | |
642 | na++; | |
643 | /* remove argv[0] b/c we just placed it in the arg list. */ | |
644 | uap->argp++; | |
645 | if (error) goto bad; | |
646 | /* Copy the argument in the interpreter first line if there | |
647 | * was one. | |
648 | */ | |
649 | if (cfarg[0]) { | |
650 | error = copyArgument(cfarg,UIO_SYSSPACE,&nc,&cp,&cc); | |
651 | na++; | |
652 | if (error) goto bad; | |
653 | } | |
654 | ||
655 | /* copy the name of the file being interpreted, gotten from | |
656 | * the structures passed in to execve. | |
657 | */ | |
658 | error = copyArgument(uap->fname,UIO_USERSPACE,&nc,&cp,&cc); | |
659 | na++; | |
660 | } | |
661 | /* Now, get rest of arguments */ | |
662 | while (uap->argp != NULL) { | |
663 | char* userArgument = (char*)fuword((caddr_t) uap->argp); | |
664 | uap->argp++; | |
665 | if (userArgument == NULL) { | |
666 | break; | |
667 | } else if ((int)userArgument == -1) { | |
668 | /* Um... why would it be -1? */ | |
669 | error = EFAULT; | |
670 | goto bad; | |
671 | } | |
672 | error = copyArgument(userArgument, UIO_USERSPACE,&nc,&cp,&cc); | |
673 | if (error) goto bad; | |
674 | na++; | |
675 | } | |
676 | /* Now, get the environment */ | |
677 | while (uap->envp != NULL) { | |
678 | char *userEnv = (char*) fuword((caddr_t) uap->envp); | |
679 | uap->envp++; | |
680 | if (userEnv == NULL) { | |
681 | break; | |
682 | } else if ((int)userEnv == -1) { | |
683 | error = EFAULT; | |
684 | goto bad; | |
685 | } | |
686 | error = copyArgument(userEnv,UIO_USERSPACE,&nc,&cp,&cc); | |
687 | if (error) goto bad; | |
688 | na++; | |
689 | ne++; | |
690 | } | |
691 | } | |
692 | ||
693 | /* make sure there are nulls are the end!! */ | |
694 | { | |
695 | int cnt = 3; | |
696 | char *mp = cp; | |
697 | ||
698 | while ( cnt-- ) | |
699 | *mp++ = '\0'; | |
700 | } | |
701 | ||
702 | /* and round up count of bytes written to next word. */ | |
703 | nc = (nc + NBPW-1) & ~(NBPW-1); | |
704 | ||
705 | if (vattr.va_fsid == classichandler_fsid && | |
706 | vattr.va_fileid == classichandler_fileid) { | |
707 | executingClassic = 1; | |
708 | } | |
709 | ||
0b4e3aa0 A |
710 | if (vfexec) { |
711 | kern_return_t result; | |
712 | ||
55e303ae | 713 | result = task_create_internal(task, FALSE, &new_task); |
0b4e3aa0 A |
714 | if (result != KERN_SUCCESS) |
715 | printf("execve: task_create failed. Code: 0x%x\n", result); | |
716 | p->task = new_task; | |
717 | set_bsdtask_info(new_task, p); | |
9bccf70c A |
718 | if (p->p_nice != 0) |
719 | resetpriority(p); | |
0b4e3aa0 A |
720 | task = new_task; |
721 | map = get_task_map(new_task); | |
722 | result = thread_create(new_task, &thr_act); | |
723 | if (result != KERN_SUCCESS) | |
724 | printf("execve: thread_create failed. Code: 0x%x\n", result); | |
725 | uthread = get_bsdthread_info(thr_act); | |
726 | } else { | |
727 | map = VM_MAP_NULL; | |
1c79356b A |
728 | } |
729 | ||
0b4e3aa0 A |
730 | /* |
731 | * Load the Mach-O file. | |
732 | */ | |
55e303ae | 733 | VOP_UNLOCK(vp, 0, p); /* XXX */ |
9bccf70c A |
734 | if(ws_cache_name) { |
735 | tws_handle_startup_file(task, cred->cr_uid, | |
55e303ae | 736 | ws_cache_name, vp, &clean_regions); |
de355530 | 737 | } |
de355530 | 738 | |
55e303ae A |
739 | vm_get_shared_region(task, &initial_region); |
740 | int parentIsClassic = (p->p_flag & P_CLASSIC); | |
741 | struct vnode *rootDir = p->p_fd->fd_rdir; | |
742 | ||
743 | if ((parentIsClassic && !executingClassic) || | |
744 | (!parentIsClassic && executingClassic)) { | |
745 | shared_region = lookup_default_shared_region( | |
746 | (int)rootDir, | |
747 | (executingClassic ? | |
748 | CPU_TYPE_POWERPC : | |
749 | machine_slot[cpu_number()].cpu_type)); | |
750 | if (shared_region == NULL) { | |
751 | shared_region_mapping_t old_region; | |
752 | shared_region_mapping_t new_region; | |
753 | vm_get_shared_region(current_task(), &old_region); | |
754 | /* grrrr... this sets current_task(), not task | |
755 | * -- they're different (usually) | |
756 | */ | |
757 | shared_file_boot_time_init( | |
758 | (int)rootDir, | |
759 | (executingClassic ? | |
760 | CPU_TYPE_POWERPC : | |
761 | machine_slot[cpu_number()].cpu_type)); | |
762 | if ( current_task() != task ) { | |
763 | vm_get_shared_region(current_task(),&new_region); | |
764 | vm_set_shared_region(task,new_region); | |
765 | vm_set_shared_region(current_task(),old_region); | |
766 | } | |
767 | } else { | |
768 | vm_set_shared_region(task, shared_region); | |
769 | } | |
770 | shared_region_mapping_dealloc(initial_region); | |
9bccf70c | 771 | } |
55e303ae | 772 | |
0b4e3aa0 | 773 | lret = load_machfile(vp, mach_header, arch_offset, |
55e303ae | 774 | arch_size, &load_result, thr_act, map, clean_regions); |
0b4e3aa0 | 775 | |
1c79356b A |
776 | if (lret != LOAD_SUCCESS) { |
777 | error = load_return_to_errno(lret); | |
55e303ae A |
778 | vrele(vp); |
779 | vp = NULL; | |
0b4e3aa0 | 780 | goto badtoolate; |
1c79356b A |
781 | } |
782 | ||
783 | /* load_machfile() maps the vnode */ | |
784 | ubc_map(vp); | |
785 | ||
786 | /* | |
787 | * deal with set[ug]id. | |
788 | */ | |
789 | p->p_flag &= ~P_SUGID; | |
790 | if (((origvattr.va_mode & VSUID) != 0 && | |
791 | p->p_ucred->cr_uid != origvattr.va_uid) | |
792 | || (origvattr.va_mode & VSGID) != 0 && | |
793 | p->p_ucred->cr_gid != origvattr.va_gid) { | |
794 | p->p_ucred = crcopy(cred); | |
795 | #if KTRACE | |
796 | /* | |
797 | * If process is being ktraced, turn off - unless | |
798 | * root set it. | |
799 | */ | |
800 | if (p->p_tracep && !(p->p_traceflag & KTRFAC_ROOT)) { | |
fa4905b1 | 801 | struct vnode *tvp = p->p_tracep; |
1c79356b A |
802 | p->p_tracep = NULL; |
803 | p->p_traceflag = 0; | |
e5568f75 A |
804 | |
805 | if (UBCINFOEXISTS(tvp)) | |
806 | ubc_rele(tvp); | |
fa4905b1 | 807 | vrele(tvp); |
1c79356b A |
808 | } |
809 | #endif | |
810 | if (origvattr.va_mode & VSUID) | |
811 | p->p_ucred->cr_uid = origvattr.va_uid; | |
812 | if (origvattr.va_mode & VSGID) | |
813 | p->p_ucred->cr_gid = origvattr.va_gid; | |
814 | ||
55e303ae A |
815 | /* |
816 | * Have mach reset the task port. We don't want | |
817 | * anyone who had the task port before a setuid | |
818 | * exec to be able to access/control the task | |
819 | * after. | |
820 | */ | |
821 | ipc_task_reset(task); | |
822 | ||
1c79356b A |
823 | p->p_flag |= P_SUGID; |
824 | ||
825 | /* Radar 2261856; setuid security hole fix */ | |
826 | /* Patch from OpenBSD: A. Ramesh */ | |
827 | /* | |
828 | * XXX For setuid processes, attempt to ensure that | |
829 | * stdin, stdout, and stderr are already allocated. | |
830 | * We do not want userland to accidentally allocate | |
831 | * descriptors in this range which has implied meaning | |
832 | * to libc. | |
833 | */ | |
834 | for (i = 0; i < 3; i++) { | |
835 | extern struct fileops vnops; | |
836 | struct nameidata nd1; | |
837 | struct file *fp; | |
838 | int indx; | |
839 | ||
840 | if (p->p_fd->fd_ofiles[i] == NULL) { | |
841 | if ((error = falloc(p, &fp, &indx)) != 0) | |
842 | continue; | |
843 | NDINIT(&nd1, LOOKUP, FOLLOW, UIO_SYSSPACE, | |
844 | "/dev/null", p); | |
845 | if ((error = vn_open(&nd1, FREAD, 0)) != 0) { | |
846 | ffree(fp); | |
847 | p->p_fd->fd_ofiles[indx] = NULL; | |
848 | break; | |
849 | } | |
850 | fp->f_flag = FREAD; | |
851 | fp->f_type = DTYPE_VNODE; | |
852 | fp->f_ops = &vnops; | |
853 | fp->f_data = (caddr_t)nd1.ni_vp; | |
854 | VOP_UNLOCK(nd1.ni_vp, 0, p); | |
855 | } | |
856 | } | |
857 | } | |
858 | p->p_cred->p_svuid = p->p_ucred->cr_uid; | |
859 | p->p_cred->p_svgid = p->p_ucred->cr_gid; | |
e5568f75 | 860 | set_security_token(p); |
1c79356b | 861 | |
55e303ae A |
862 | KNOTE(&p->p_klist, NOTE_EXEC); |
863 | ||
9bccf70c | 864 | if (!vfexec && (p->p_flag & P_TRACED)) |
1c79356b | 865 | psignal(p, SIGTRAP); |
1c79356b A |
866 | |
867 | if (error) { | |
55e303ae A |
868 | vrele(vp); |
869 | vp = NULL; | |
0b4e3aa0 | 870 | goto badtoolate; |
1c79356b | 871 | } |
55e303ae | 872 | VOP_LOCK(vp, LK_EXCLUSIVE | LK_RETRY, p); /* XXX */ |
1c79356b A |
873 | vput(vp); |
874 | vp = NULL; | |
875 | ||
876 | if (load_result.unixproc && | |
0b4e3aa0 A |
877 | create_unix_stack(get_task_map(task), |
878 | load_result.user_stack, load_result.customstack, p)) { | |
1c79356b | 879 | error = load_return_to_errno(LOAD_NOSPACE); |
0b4e3aa0 A |
880 | goto badtoolate; |
881 | } | |
882 | ||
883 | if (vfexec) { | |
884 | uthread->uu_ar0 = (void *)get_user_regs(thr_act); | |
1c79356b A |
885 | } |
886 | ||
887 | /* | |
888 | * Copy back arglist if necessary. | |
889 | */ | |
890 | ||
0b4e3aa0 | 891 | |
55e303ae | 892 | ucp = (int)p->user_stack; |
0b4e3aa0 A |
893 | if (vfexec) { |
894 | old_map = vm_map_switch(get_task_map(task)); | |
895 | } | |
1c79356b A |
896 | if (load_result.unixproc) { |
897 | int pathptr; | |
898 | ||
899 | ucp = ucp - nc - NBPW; /* begining of the STRING AREA */ | |
900 | ||
901 | /* | |
902 | * Support for new app package launching for Mac OS X allocates | |
903 | * the "path" at the begining of the execargs buffer. | |
904 | * copy it just before the string area. | |
905 | */ | |
1c79356b | 906 | len = 0; |
55e303ae | 907 | pathptr = ucp - ((savedpathlen + NBPW-1) & ~(NBPW-1)); |
1c79356b | 908 | error = copyoutstr(savedpath, (caddr_t)pathptr, |
55e303ae A |
909 | (unsigned)savedpathlen, (size_t *)&len); |
910 | savedpathlen = (savedpathlen + NBPW-1) & ~(NBPW-1); | |
911 | ||
0b4e3aa0 A |
912 | if (error) { |
913 | if (vfexec) | |
914 | vm_map_switch(old_map); | |
915 | goto badtoolate; | |
916 | } | |
55e303ae A |
917 | |
918 | /* | |
919 | * Record the size of the arguments area so that | |
920 | * sysctl_procargs() can return the argument area without having | |
921 | * to parse the arguments. | |
922 | */ | |
923 | p->p_argslen = (int)p->user_stack - pathptr; | |
924 | p->p_argc = na - ne; /* save argc for sysctl_procargs() */ | |
925 | ||
1c79356b A |
926 | /* Save a NULL pointer below it */ |
927 | (void) suword((caddr_t)(pathptr - NBPW), 0); | |
928 | ||
929 | /* Save the pointer to "path" just below it */ | |
930 | (void) suword((caddr_t)(pathptr - 2*NBPW), pathptr); | |
931 | ||
932 | /* | |
933 | * na includes arg[] and env[]. | |
934 | * NBPW for 2 NULL one each ofter arg[argc -1] and env[n] | |
935 | * NBPW for argc | |
936 | * skip over saved path, NBPW for pointer to path, | |
937 | * and NBPW for the NULL after pointer to path. | |
938 | */ | |
939 | ap = ucp - na*NBPW - 3*NBPW - savedpathlen - 2*NBPW; | |
9bccf70c A |
940 | #if defined(ppc) |
941 | thread_setuserstack(thr_act, ap); /* Set the stack */ | |
942 | #else | |
1c79356b | 943 | uthread->uu_ar0[SP] = ap; |
9bccf70c | 944 | #endif |
1c79356b A |
945 | (void) suword((caddr_t)ap, na-ne); /* argc */ |
946 | nc = 0; | |
947 | cc = 0; | |
948 | ||
949 | cp = (char *) execargsp; | |
950 | cc = NCARGS - savedpathlen - 2*NBPW; | |
951 | ps.ps_argvstr = (char *)ucp; /* first argv string */ | |
952 | ps.ps_nargvstr = na - ne; /* argc */ | |
953 | for (;;) { | |
954 | ap += NBPW; | |
955 | if (na == ne) { | |
956 | (void) suword((caddr_t)ap, 0); | |
957 | ap += NBPW; | |
958 | ps.ps_envstr = (char *)ucp; | |
959 | ps.ps_nenvstr = ne; | |
960 | } | |
961 | if (--na < 0) | |
962 | break; | |
963 | (void) suword((caddr_t)ap, ucp); | |
964 | do { | |
965 | error = copyoutstr(cp, (caddr_t)ucp, | |
55e303ae | 966 | (unsigned)cc, (size_t *)&len); |
1c79356b A |
967 | ucp += len; |
968 | cp += len; | |
969 | nc += len; | |
970 | cc -= len; | |
971 | } while (error == ENAMETOOLONG); | |
972 | if (error == EFAULT) | |
973 | break; /* bad stack - user's problem */ | |
974 | } | |
975 | (void) suword((caddr_t)ap, 0); | |
976 | } | |
977 | ||
978 | if (load_result.dynlinker) { | |
9bccf70c A |
979 | #if defined(ppc) |
980 | ap = thread_adjuserstack(thr_act, -4); /* Adjust the stack */ | |
981 | #else | |
1c79356b | 982 | ap = uthread->uu_ar0[SP] -= 4; |
9bccf70c | 983 | #endif |
1c79356b A |
984 | (void) suword((caddr_t)ap, load_result.mach_header); |
985 | } | |
986 | ||
0b4e3aa0 A |
987 | if (vfexec) { |
988 | vm_map_switch(old_map); | |
989 | } | |
9bccf70c A |
990 | #if defined(ppc) |
991 | thread_setentrypoint(thr_act, load_result.entry_point); /* Set the entry point */ | |
992 | #elif defined(i386) | |
1c79356b A |
993 | uthread->uu_ar0[PC] = load_result.entry_point; |
994 | #else | |
995 | #error architecture not implemented! | |
996 | #endif | |
997 | ||
998 | /* Stop profiling */ | |
999 | stopprofclock(p); | |
1000 | ||
1001 | /* | |
1002 | * Reset signal state. | |
1003 | */ | |
9bccf70c | 1004 | execsigs(p, thr_act); |
1c79356b A |
1005 | |
1006 | /* | |
1007 | * Close file descriptors | |
1008 | * which specify close-on-exec. | |
1009 | */ | |
1010 | fdexec(p); | |
55e303ae A |
1011 | |
1012 | /* | |
1013 | * need to cancel async IO requests that can be cancelled and wait for those | |
1014 | * already active. MAY BLOCK! | |
1015 | */ | |
1016 | _aio_exec( p ); | |
1017 | ||
1c79356b | 1018 | /* FIXME: Till vmspace inherit is fixed: */ |
9bccf70c | 1019 | if (!vfexec && p->vm_shm) |
55e303ae | 1020 | shmexec(p); |
9bccf70c A |
1021 | /* Clean up the semaphores */ |
1022 | semexit(p); | |
1c79356b A |
1023 | |
1024 | /* | |
1025 | * Remember file name for accounting. | |
1026 | */ | |
1027 | p->p_acflag &= ~AFORK; | |
55e303ae A |
1028 | /* If the translated name isn't NULL, then we want to use |
1029 | * that translated name as the name we show as the "real" name. | |
1030 | * Otherwise, use the name passed into exec. | |
1031 | */ | |
1032 | if (0 != binaryWithClassicName[0]) { | |
1033 | bcopy((caddr_t)binaryWithClassicName, (caddr_t)p->p_comm, | |
1034 | sizeof(binaryWithClassicName)); | |
1035 | } else { | |
1036 | if (nd.ni_cnd.cn_namelen > MAXCOMLEN) | |
1037 | nd.ni_cnd.cn_namelen = MAXCOMLEN; | |
1038 | bcopy((caddr_t)nd.ni_cnd.cn_nameptr, (caddr_t)p->p_comm, | |
1039 | (unsigned)nd.ni_cnd.cn_namelen); | |
1040 | p->p_comm[nd.ni_cnd.cn_namelen] = '\0'; | |
1041 | } | |
1c79356b A |
1042 | |
1043 | { | |
1044 | /* This is for kdebug */ | |
1045 | long dbg_arg1, dbg_arg2, dbg_arg3, dbg_arg4; | |
1046 | ||
1047 | /* Collect the pathname for tracing */ | |
1048 | kdbg_trace_string(p, &dbg_arg1, &dbg_arg2, &dbg_arg3, &dbg_arg4); | |
0b4e3aa0 | 1049 | |
55e303ae A |
1050 | |
1051 | ||
0b4e3aa0 | 1052 | if (vfexec) |
55e303ae A |
1053 | { |
1054 | KERNEL_DEBUG_CONSTANT1((TRACEDBG_CODE(DBG_TRACE_DATA, 2)) | DBG_FUNC_NONE, | |
1055 | p->p_pid ,0,0,0, (unsigned int)thr_act); | |
0b4e3aa0 | 1056 | KERNEL_DEBUG_CONSTANT1((TRACEDBG_CODE(DBG_TRACE_STRING, 2)) | DBG_FUNC_NONE, |
55e303ae A |
1057 | dbg_arg1, dbg_arg2, dbg_arg3, dbg_arg4, (unsigned int)thr_act); |
1058 | } | |
0b4e3aa0 | 1059 | else |
55e303ae A |
1060 | { |
1061 | KERNEL_DEBUG_CONSTANT((TRACEDBG_CODE(DBG_TRACE_DATA, 2)) | DBG_FUNC_NONE, | |
1062 | p->p_pid ,0,0,0,0); | |
0b4e3aa0 A |
1063 | KERNEL_DEBUG_CONSTANT((TRACEDBG_CODE(DBG_TRACE_STRING, 2)) | DBG_FUNC_NONE, |
1064 | dbg_arg1, dbg_arg2, dbg_arg3, dbg_arg4, 0); | |
55e303ae | 1065 | } |
1c79356b A |
1066 | } |
1067 | ||
55e303ae A |
1068 | if (executingClassic) |
1069 | p->p_flag |= P_CLASSIC | P_AFFINITY; | |
1070 | else | |
1071 | p->p_flag &= ~P_CLASSIC; | |
1072 | ||
1c79356b A |
1073 | /* |
1074 | * mark as execed, wakeup the process that vforked (if any) and tell | |
1075 | * it that it now has it's own resources back | |
1076 | */ | |
1077 | p->p_flag |= P_EXEC; | |
1078 | if (p->p_pptr && (p->p_flag & P_PPWAIT)) { | |
1079 | p->p_flag &= ~P_PPWAIT; | |
1080 | wakeup((caddr_t)p->p_pptr); | |
1081 | } | |
1082 | ||
0b4e3aa0 A |
1083 | if (vfexec && (p->p_flag & P_TRACED)) { |
1084 | psignal_vfork(p, new_task, thr_act, SIGTRAP); | |
1085 | } | |
1086 | ||
1087 | badtoolate: | |
1088 | if (vfexec) { | |
0b4e3aa0 A |
1089 | task_deallocate(new_task); |
1090 | act_deallocate(thr_act); | |
1091 | if (error) | |
1092 | error = 0; | |
1093 | } | |
1c79356b A |
1094 | bad: |
1095 | FREE_ZONE(nd.ni_cnd.cn_pnbuf, nd.ni_cnd.cn_pnlen, M_NAMEI); | |
1096 | if (vp) | |
1097 | vput(vp); | |
1098 | bad1: | |
1c79356b | 1099 | if (execargs) |
765c9de3 | 1100 | execargs_free(execargs); |
0b4e3aa0 A |
1101 | if (!error && vfexec) { |
1102 | vfork_return(current_act(), p->p_pptr, p, retval); | |
9bccf70c | 1103 | (void) thread_resume(thr_act); |
0b4e3aa0 A |
1104 | return(0); |
1105 | } | |
1c79356b A |
1106 | return(error); |
1107 | } | |
1108 | ||
1109 | ||
1110 | #define unix_stack_size(p) (p->p_rlimit[RLIMIT_STACK].rlim_cur) | |
1111 | ||
1112 | kern_return_t | |
0b4e3aa0 | 1113 | create_unix_stack(map, user_stack, customstack, p) |
1c79356b A |
1114 | vm_map_t map; |
1115 | vm_offset_t user_stack; | |
0b4e3aa0 | 1116 | int customstack; |
1c79356b A |
1117 | struct proc *p; |
1118 | { | |
1119 | vm_size_t size; | |
1120 | vm_offset_t addr; | |
1121 | ||
55e303ae | 1122 | p->user_stack = (caddr_t)user_stack; |
0b4e3aa0 | 1123 | if (!customstack) { |
55e303ae A |
1124 | size = round_page_64(unix_stack_size(p)); |
1125 | addr = trunc_page_32(user_stack - size); | |
1126 | return (vm_allocate(map, &addr, size, | |
1127 | VM_MAKE_TAG(VM_MEMORY_STACK) | FALSE)); | |
0b4e3aa0 A |
1128 | } else |
1129 | return(KERN_SUCCESS); | |
1c79356b A |
1130 | } |
1131 | ||
1132 | #include <sys/reboot.h> | |
1133 | ||
1134 | char init_program_name[128] = "/sbin/mach_init\0"; | |
1135 | ||
1136 | char init_args[128] = ""; | |
1137 | ||
1138 | struct execve_args init_exec_args; | |
1139 | int init_attempts = 0; | |
1140 | ||
1141 | ||
1142 | void | |
1143 | load_init_program(p) | |
1144 | struct proc *p; | |
1145 | { | |
1146 | vm_offset_t init_addr; | |
1147 | int *old_ap; | |
1148 | char *argv[3]; | |
1149 | int error; | |
1150 | register_t retval[2]; | |
1151 | struct uthread * ut; | |
1152 | ||
1c79356b A |
1153 | error = 0; |
1154 | ||
1155 | /* init_args are copied in string form directly from bootstrap */ | |
1156 | ||
1157 | do { | |
1158 | if (boothowto & RB_INITNAME) { | |
1159 | printf("init program? "); | |
1160 | #if FIXME /* [ */ | |
1161 | gets(init_program_name, init_program_name); | |
1162 | #endif /* FIXME ] */ | |
1163 | } | |
1164 | ||
1165 | if (error && ((boothowto & RB_INITNAME) == 0) && | |
1166 | (init_attempts == 1)) { | |
1167 | static char other_init[] = "/etc/mach_init"; | |
1168 | printf("Load of %s, errno %d, trying %s\n", | |
1169 | init_program_name, error, other_init); | |
1170 | error = 0; | |
1171 | bcopy(other_init, init_program_name, | |
1172 | sizeof(other_init)); | |
1173 | } | |
1174 | ||
1175 | init_attempts++; | |
1176 | ||
1177 | if (error) { | |
1178 | printf("Load of %s failed, errno %d\n", | |
1179 | init_program_name, error); | |
1180 | error = 0; | |
1181 | boothowto |= RB_INITNAME; | |
1182 | continue; | |
1183 | } | |
1184 | ||
1185 | /* | |
1186 | * Copy out program name. | |
1187 | */ | |
1188 | ||
1189 | init_addr = VM_MIN_ADDRESS; | |
1190 | (void) vm_allocate(current_map(), &init_addr, | |
1191 | PAGE_SIZE, TRUE); | |
1192 | if (init_addr == 0) | |
1193 | init_addr++; | |
1194 | (void) copyout((caddr_t) init_program_name, | |
1195 | (caddr_t) (init_addr), | |
1196 | (unsigned) sizeof(init_program_name)+1); | |
1197 | ||
1198 | argv[0] = (char *) init_addr; | |
1199 | init_addr += sizeof(init_program_name); | |
1200 | init_addr = (vm_offset_t)ROUND_PTR(char, init_addr); | |
1201 | ||
1202 | /* | |
1203 | * Put out first (and only) argument, similarly. | |
1204 | * Assumes everything fits in a page as allocated | |
1205 | * above. | |
1206 | */ | |
1207 | ||
1208 | (void) copyout((caddr_t) init_args, | |
1209 | (caddr_t) (init_addr), | |
1210 | (unsigned) sizeof(init_args)); | |
1211 | ||
1212 | argv[1] = (char *) init_addr; | |
1213 | init_addr += sizeof(init_args); | |
1214 | init_addr = (vm_offset_t)ROUND_PTR(char, init_addr); | |
1215 | ||
1216 | /* | |
1217 | * Null-end the argument list | |
1218 | */ | |
1219 | ||
1220 | argv[2] = (char *) 0; | |
1221 | ||
1222 | /* | |
1223 | * Copy out the argument list. | |
1224 | */ | |
1225 | ||
1226 | (void) copyout((caddr_t) argv, | |
1227 | (caddr_t) (init_addr), | |
1228 | (unsigned) sizeof(argv)); | |
1229 | ||
1230 | /* | |
1231 | * Set up argument block for fake call to execve. | |
1232 | */ | |
1233 | ||
1234 | init_exec_args.fname = argv[0]; | |
1235 | init_exec_args.argp = (char **) init_addr; | |
1236 | init_exec_args.envp = 0; | |
1237 | ||
1238 | /* So that mach_init task | |
1239 | * is set with uid,gid 0 token | |
1240 | */ | |
1241 | set_security_token(p); | |
1242 | ||
1243 | error = execve(p,&init_exec_args,retval); | |
1244 | } while (error); | |
1c79356b A |
1245 | } |
1246 | ||
1247 | /* | |
1248 | * Convert a load_return_t to an errno. | |
1249 | */ | |
1250 | static int | |
1251 | load_return_to_errno(load_return_t lrtn) | |
1252 | { | |
1253 | switch (lrtn) { | |
1254 | case LOAD_SUCCESS: | |
55e303ae | 1255 | return 0; |
1c79356b A |
1256 | case LOAD_BADARCH: |
1257 | return EBADARCH; | |
1258 | case LOAD_BADMACHO: | |
1259 | return EBADMACHO; | |
1260 | case LOAD_SHLIB: | |
1261 | return ESHLIBVERS; | |
1262 | case LOAD_NOSPACE: | |
55e303ae | 1263 | case LOAD_RESOURCE: |
1c79356b A |
1264 | return ENOMEM; |
1265 | case LOAD_PROTECT: | |
1266 | return EACCES; | |
55e303ae A |
1267 | case LOAD_ENOENT: |
1268 | return ENOENT; | |
1269 | case LOAD_IOERROR: | |
1270 | return EIO; | |
1c79356b A |
1271 | case LOAD_FAILURE: |
1272 | default: | |
1273 | return EBADEXEC; | |
1274 | } | |
1275 | } | |
1276 | ||
1277 | /* | |
1278 | * exec_check_access() | |
1279 | */ | |
1280 | int | |
1281 | check_exec_access(p, vp, vap) | |
1282 | struct proc *p; | |
1283 | struct vnode *vp; | |
1284 | struct vattr *vap; | |
1285 | { | |
1286 | int flag; | |
1287 | int error; | |
1288 | ||
1289 | if (error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p)) | |
1290 | return (error); | |
1291 | flag = p->p_flag; | |
1292 | if (flag & P_TRACED) { | |
1293 | if (error = VOP_ACCESS(vp, VREAD, p->p_ucred, p)) | |
1294 | return (error); | |
1295 | } | |
1296 | if (vp->v_type != VREG || | |
1297 | (vap->va_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) == 0) | |
1298 | return (EACCES); | |
1299 | return (0); | |
1300 | } | |
1301 | ||
765c9de3 A |
1302 | #include <mach/mach_types.h> |
1303 | #include <mach/vm_prot.h> | |
1304 | #include <mach/semaphore.h> | |
1305 | #include <mach/sync_policy.h> | |
1306 | #include <kern/clock.h> | |
1307 | #include <mach/kern_return.h> | |
1308 | ||
1309 | extern semaphore_t execve_semaphore; | |
1310 | ||
1311 | static int | |
1312 | execargs_alloc(addrp) | |
1313 | vm_offset_t *addrp; | |
1314 | { | |
1315 | kern_return_t kret; | |
1316 | ||
1317 | kret = semaphore_wait(execve_semaphore); | |
1318 | if (kret != KERN_SUCCESS) | |
1319 | switch (kret) { | |
1320 | default: | |
1321 | return (EINVAL); | |
1322 | case KERN_INVALID_ADDRESS: | |
1323 | case KERN_PROTECTION_FAILURE: | |
1324 | return (EACCES); | |
1325 | case KERN_ABORTED: | |
1326 | case KERN_OPERATION_TIMED_OUT: | |
1327 | return (EINTR); | |
1328 | } | |
1329 | ||
1330 | kret = kmem_alloc_pageable(bsd_pageable_map, addrp, NCARGS); | |
55e303ae A |
1331 | if (kret != KERN_SUCCESS) { |
1332 | semaphore_signal(execve_semaphore); | |
765c9de3 | 1333 | return (ENOMEM); |
55e303ae | 1334 | } |
765c9de3 A |
1335 | return (0); |
1336 | } | |
1337 | ||
1338 | static int | |
1339 | execargs_free(addr) | |
1340 | vm_offset_t addr; | |
1341 | { | |
1342 | kern_return_t kret; | |
1343 | ||
1344 | kmem_free(bsd_pageable_map, addr, NCARGS); | |
1345 | ||
1346 | kret = semaphore_signal(execve_semaphore); | |
1347 | switch (kret) { | |
1348 | case KERN_INVALID_ADDRESS: | |
1349 | case KERN_PROTECTION_FAILURE: | |
1350 | return (EINVAL); | |
1351 | case KERN_ABORTED: | |
1352 | case KERN_OPERATION_TIMED_OUT: | |
1353 | return (EINTR); | |
1354 | case KERN_SUCCESS: | |
1355 | return(0); | |
1356 | default: | |
1357 | return (EINVAL); | |
1358 | } | |
1359 | } |