]>
Commit | Line | Data |
---|---|---|
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 | ||
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); | |
765c9de3 A |
115 | static int execargs_alloc(vm_offset_t *addrp); |
116 | static int execargs_free(vm_offset_t addr); | |
1c79356b A |
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; | |
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 | ||
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 | ||
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 | ||
754 | badtoolate: | |
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 |
762 | bad: |
763 | FREE_ZONE(nd.ni_cnd.cn_pnbuf, nd.ni_cnd.cn_pnlen, M_NAMEI); | |
764 | if (vp) | |
765 | vput(vp); | |
766 | bad1: | |
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 | ||
779 | kern_return_t | |
0b4e3aa0 | 780 | create_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 | ||
800 | char init_program_name[128] = "/sbin/mach_init\0"; | |
801 | ||
802 | char init_args[128] = ""; | |
803 | ||
804 | struct execve_args init_exec_args; | |
805 | int init_attempts = 0; | |
806 | ||
807 | ||
808 | void | |
809 | load_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 | */ | |
920 | static int | |
921 | load_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 | */ | |
946 | int | |
947 | check_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 | ||
975 | extern semaphore_t execve_semaphore; | |
976 | ||
977 | static int | |
978 | execargs_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 | ||
1003 | static int | |
1004 | execargs_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 |