]>
Commit | Line | Data |
---|---|---|
1c79356b | 1 | /* |
5d5c5d0d A |
2 | * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved. |
3 | * | |
8f6c56a5 | 4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ |
1c79356b | 5 | * |
8f6c56a5 A |
6 | * This file contains Original Code and/or Modifications of Original Code |
7 | * as defined in and that are subject to the Apple Public Source License | |
8 | * Version 2.0 (the 'License'). You may not use this file except in | |
9 | * compliance with the License. The rights granted to you under the License | |
10 | * may not be used to create, or enable the creation or redistribution of, | |
11 | * unlawful or unlicensed copies of an Apple operating system, or to | |
12 | * circumvent, violate, or enable the circumvention or violation of, any | |
13 | * terms of an Apple operating system software license agreement. | |
14 | * | |
15 | * Please obtain a copy of the License at | |
16 | * http://www.opensource.apple.com/apsl/ and read it before using this file. | |
17 | * | |
18 | * The Original Code and all software distributed under the License are | |
19 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
20 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
21 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
22 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. | |
23 | * Please see the License for the specific language governing rights and | |
8ad349bb | 24 | * limitations under the License. |
8f6c56a5 A |
25 | * |
26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ | |
1c79356b A |
27 | */ |
28 | /* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */ | |
29 | /* | |
30 | * Mach Operating System | |
31 | * Copyright (c) 1987 Carnegie-Mellon University | |
32 | * All rights reserved. The CMU software License Agreement specifies | |
33 | * the terms and conditions for use and redistribution. | |
34 | */ | |
35 | ||
36 | #include <cputypes.h> | |
37 | ||
38 | /*- | |
39 | * Copyright (c) 1982, 1986, 1991, 1993 | |
40 | * The Regents of the University of California. All rights reserved. | |
41 | * (c) UNIX System Laboratories, Inc. | |
42 | * All or some portions of this file are derived from material licensed | |
43 | * to the University of California by American Telephone and Telegraph | |
44 | * Co. or Unix System Laboratories, Inc. and are reproduced herein with | |
45 | * the permission of UNIX System Laboratories, Inc. | |
46 | * | |
47 | * Redistribution and use in source and binary forms, with or without | |
48 | * modification, are permitted provided that the following conditions | |
49 | * are met: | |
50 | * 1. Redistributions of source code must retain the above copyright | |
51 | * notice, this list of conditions and the following disclaimer. | |
52 | * 2. Redistributions in binary form must reproduce the above copyright | |
53 | * notice, this list of conditions and the following disclaimer in the | |
54 | * documentation and/or other materials provided with the distribution. | |
55 | * 3. All advertising materials mentioning features or use of this software | |
56 | * must display the following acknowledgement: | |
57 | * This product includes software developed by the University of | |
58 | * California, Berkeley and its contributors. | |
59 | * 4. Neither the name of the University nor the names of its contributors | |
60 | * may be used to endorse or promote products derived from this software | |
61 | * without specific prior written permission. | |
62 | * | |
63 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND | |
64 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
65 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
66 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE | |
67 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
68 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
69 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
70 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
71 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
72 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
73 | * SUCH DAMAGE. | |
74 | * | |
75 | * from: @(#)kern_exec.c 8.1 (Berkeley) 6/10/93 | |
76 | */ | |
77 | #include <machine/reg.h> | |
78 | ||
79 | #include <sys/param.h> | |
80 | #include <sys/systm.h> | |
81 | #include <sys/filedesc.h> | |
82 | #include <sys/kernel.h> | |
91447636 A |
83 | #include <sys/proc_internal.h> |
84 | #include <sys/kauth.h> | |
1c79356b | 85 | #include <sys/user.h> |
1c79356b A |
86 | #include <sys/socketvar.h> |
87 | #include <sys/malloc.h> | |
88 | #include <sys/namei.h> | |
91447636 A |
89 | #include <sys/mount_internal.h> |
90 | #include <sys/vnode_internal.h> | |
91 | #include <sys/file_internal.h> | |
1c79356b | 92 | #include <sys/stat.h> |
91447636 | 93 | #include <sys/uio_internal.h> |
1c79356b A |
94 | #include <sys/acct.h> |
95 | #include <sys/exec.h> | |
96 | #include <sys/kdebug.h> | |
97 | #include <sys/signal.h> | |
55e303ae | 98 | #include <sys/aio_kern.h> |
91447636 A |
99 | #include <sys/sysproto.h> |
100 | #include <sys/shm_internal.h> /* shmexec() */ | |
101 | #include <sys/ubc_internal.h> /* ubc_map() */ | |
1c79356b | 102 | |
e5568f75 A |
103 | #include <bsm/audit_kernel.h> |
104 | ||
91447636 A |
105 | #include <mach/mach_types.h> |
106 | #include <mach/task.h> | |
107 | #include <mach/thread_act.h> | |
108 | #include <mach/vm_map.h> | |
109 | #include <mach/mach_vm.h> | |
1c79356b A |
110 | #include <mach/vm_param.h> |
111 | ||
112 | #include <vm/vm_map.h> | |
113 | #include <vm/vm_kern.h> | |
91447636 A |
114 | #include <vm/vm_pager.h> |
115 | #include <vm/vm_kern.h> | |
116 | #include <vm/task_working_set.h> | |
9bccf70c | 117 | #include <vm/vm_shared_memory_server.h> |
1c79356b | 118 | |
91447636 A |
119 | /* |
120 | * Mach things for which prototypes are unavailable from Mach headers | |
121 | */ | |
122 | void ipc_task_reset( | |
123 | task_t task); | |
124 | ||
125 | extern struct savearea *get_user_regs(thread_t); | |
126 | ||
127 | ||
1c79356b A |
128 | #include <kern/thread.h> |
129 | #include <kern/task.h> | |
1c79356b A |
130 | #include <kern/ast.h> |
131 | #include <kern/mach_loader.h> | |
132 | #include <mach-o/fat.h> | |
133 | #include <mach-o/loader.h> | |
134 | #include <machine/vmparam.h> | |
9bccf70c A |
135 | #if KTRACE |
136 | #include <sys/ktrace.h> | |
137 | #endif | |
91447636 A |
138 | #include <sys/imgact.h> |
139 | ||
140 | ||
141 | /* | |
142 | * SIZE_MAXPTR The maximum size of a user space pointer, in bytes | |
143 | * SIZE_IMG_STRSPACE The available string space, minus two pointers; we | |
144 | * define it interms of the maximum, since we don't | |
145 | * know the pointer size going in, until after we've | |
146 | * parsed the executable image. | |
147 | */ | |
148 | #define SIZE_MAXPTR 8 /* 64 bits */ | |
149 | #define SIZE_IMG_STRSPACE (NCARGS - 2 * SIZE_MAXPTR) | |
9bccf70c A |
150 | |
151 | int app_profile = 0; | |
1c79356b A |
152 | |
153 | extern vm_map_t bsd_pageable_map; | |
91447636 | 154 | extern struct fileops vnops; |
1c79356b A |
155 | |
156 | #define ROUND_PTR(type, addr) \ | |
157 | (type *)( ( (unsigned)(addr) + 16 - 1) \ | |
158 | & ~(16 - 1) ) | |
159 | ||
91447636 A |
160 | struct image_params; /* Forward */ |
161 | static int exec_copyout_strings(struct image_params *imgp, user_addr_t *stackp); | |
1c79356b | 162 | static int load_return_to_errno(load_return_t lrtn); |
91447636 A |
163 | static int execargs_alloc(struct image_params *imgp); |
164 | static int execargs_free(struct image_params *imgp); | |
165 | static int exec_check_permissions(struct image_params *imgp); | |
166 | static int exec_extract_strings(struct image_params *imgp); | |
167 | static int exec_handle_sugid(struct image_params *imgp); | |
a3d08fcd A |
168 | static int sugid_scripts = 0; |
169 | SYSCTL_INT (_kern, OID_AUTO, sugid_scripts, CTLFLAG_RW, &sugid_scripts, 0, ""); | |
91447636 A |
170 | static kern_return_t create_unix_stack(vm_map_t map, user_addr_t user_stack, |
171 | int customstack, struct proc *p); | |
172 | static int copyoutptr(user_addr_t ua, user_addr_t ptr, int ptr_size); | |
173 | ||
174 | /* XXX forward; should be in headers, but can't be for one reason or another */ | |
21362eb3 | 175 | extern int grade_binary(cpu_type_t exectype, cpu_subtype_t execsubtype); |
91447636 A |
176 | extern void vfork_return(thread_t th_act, |
177 | struct proc * p, | |
178 | struct proc *p2, | |
179 | register_t *retval); | |
1c79356b | 180 | |
21362eb3 A |
181 | |
182 | extern char classichandler[32]; | |
183 | extern uint32_t classichandler_fsid; | |
184 | extern long classichandler_fileid; | |
185 | ||
186 | ||
55e303ae | 187 | /* |
91447636 A |
188 | * exec_add_string |
189 | * | |
190 | * Add the requested string to the string space area. | |
191 | * | |
192 | * Parameters; struct image_params * image parameter block | |
193 | * user_addr_t string to add to strings area | |
194 | * uio_seg segment where string is located | |
195 | * | |
196 | * Returns: 0 Success | |
197 | * !0 Failure errno from copyinstr() | |
198 | * | |
199 | * Implicit returns: | |
200 | * (imgp->ip_strendp) updated location of next add, if any | |
201 | * (imgp->ip_strspace) updated byte count of space remaining | |
55e303ae | 202 | */ |
91447636 A |
203 | static int |
204 | exec_add_string(struct image_params *imgp, user_addr_t str, /*uio_seg*/int seg) | |
205 | { | |
55e303ae | 206 | int error = 0; |
91447636 | 207 | |
55e303ae A |
208 | do { |
209 | size_t len = 0; | |
91447636 | 210 | if (imgp->ip_strspace <= 0) { |
55e303ae A |
211 | error = E2BIG; |
212 | break; | |
213 | } | |
91447636 A |
214 | if (IS_UIO_SYS_SPACE(seg)) { |
215 | char *kstr = CAST_DOWN(char *,str); /* SAFE */ | |
216 | error = copystr(kstr, imgp->ip_strendp, imgp->ip_strspace, &len); | |
55e303ae | 217 | } else { |
91447636 | 218 | error = copyinstr(str, imgp->ip_strendp, imgp->ip_strspace, |
55e303ae A |
219 | &len); |
220 | } | |
91447636 A |
221 | imgp->ip_strendp += len; |
222 | imgp->ip_strspace -= len; | |
55e303ae | 223 | } while (error == ENAMETOOLONG); |
91447636 | 224 | |
55e303ae A |
225 | return error; |
226 | } | |
227 | ||
91447636 A |
228 | /* |
229 | * exec_save_path | |
230 | * | |
231 | * To support new app package launching for Mac OS X, the dyld needs the | |
232 | * first argument to execve() stored on the user stack. | |
233 | * | |
234 | * Save the executable path name at the top of the strings area and set | |
235 | * the argument vector pointer to the location following that to indicate | |
236 | * the start of the argument and environment tuples, setting the remaining | |
237 | * string space count to the size of the string area minus the path length | |
238 | * and a reserve for two pointers. | |
239 | * | |
240 | * Parameters; struct image_params * image parameter block | |
241 | * char * path used to invoke program | |
242 | * uio_seg segment where path is located | |
243 | * | |
244 | * Returns: int 0 Success | |
245 | * !0 Failure: error number | |
246 | * Implicit returns: | |
247 | * (imgp->ip_strings) saved path | |
248 | * (imgp->ip_strspace) space remaining in ip_strings | |
249 | * (imgp->ip_argv) beginning of argument list | |
250 | * (imgp->ip_strendp) start of remaining copy area | |
251 | * | |
252 | * Note: We have to do this before the initial namei() since in the | |
253 | * path contains symbolic links, namei() will overwrite the | |
254 | * original path buffer contents. If the last symbolic link | |
255 | * resolved was a relative pathname, we would lose the original | |
256 | * "path", which could be an absolute pathname. This might be | |
257 | * unacceptable for dyld. | |
258 | */ | |
259 | static int | |
260 | exec_save_path(struct image_params *imgp, user_addr_t path, /*uio_seg*/int seg) | |
1c79356b | 261 | { |
91447636 A |
262 | int error; |
263 | size_t len; | |
264 | char *kpath = CAST_DOWN(char *,path); /* SAFE */ | |
265 | ||
266 | imgp->ip_strendp = imgp->ip_strings; | |
267 | imgp->ip_strspace = SIZE_IMG_STRSPACE; | |
268 | ||
269 | len = MIN(MAXPATHLEN, imgp->ip_strspace); | |
270 | ||
271 | switch( seg) { | |
272 | case UIO_USERSPACE32: | |
273 | case UIO_USERSPACE64: /* Same for copyin()... */ | |
274 | error = copyinstr(path, imgp->ip_strings, len, &len); | |
275 | break; | |
276 | case UIO_SYSSPACE32: | |
277 | error = copystr(kpath, imgp->ip_strings, len, &len); | |
278 | break; | |
279 | default: | |
280 | error = EFAULT; | |
281 | break; | |
282 | } | |
283 | ||
284 | if (!error) { | |
285 | imgp->ip_strendp += len; | |
286 | imgp->ip_strspace -= len; | |
287 | imgp->ip_argv = imgp->ip_strendp; | |
288 | } | |
289 | ||
290 | return(error); | |
291 | } | |
292 | ||
293 | ||
294 | ||
295 | /* | |
296 | * exec_shell_imgact | |
297 | * | |
298 | * Image activator for interpreter scripts. If the image begins with the | |
299 | * characters "#!", then it is an interpreter script. Verify that we are | |
21362eb3 | 300 | * not already executing in Classic mode, and that the length of the script |
91447636 A |
301 | * line indicating the interpreter is not in excess of the maximum allowed |
302 | * size. If this is the case, then break out the arguments, if any, which | |
303 | * are separated by white space, and copy them into the argument save area | |
304 | * as if they were provided on the command line before all other arguments. | |
305 | * The line ends when we encounter a comment character ('#') or newline. | |
306 | * | |
307 | * Parameters; struct image_params * image parameter block | |
308 | * | |
309 | * Returns: -1 not an interpreter (keep looking) | |
310 | * -3 Success: interpreter: relookup | |
311 | * >0 Failure: interpreter: error number | |
312 | * | |
313 | * A return value other than -1 indicates subsequent image activators should | |
314 | * not be given the opportunity to attempt to activate the image. | |
315 | */ | |
316 | static int | |
317 | exec_shell_imgact(struct image_params *imgp) | |
318 | { | |
319 | char *vdata = imgp->ip_vdata; | |
320 | char *ihp; | |
321 | char *line_endp; | |
322 | char *interp; | |
323 | ||
324 | /* | |
325 | * Make sure it's a shell script. If we've already redirected | |
326 | * from an interpreted file once, don't do it again. | |
327 | * | |
21362eb3 A |
328 | * Note: We disallow Classic, since the expectation is that we |
329 | * may run a Classic interpreter, but not an interpret a Classic | |
91447636 | 330 | * image. This is consistent with historical behaviour. |
55e303ae | 331 | */ |
91447636 A |
332 | if (vdata[0] != '#' || |
333 | vdata[1] != '!' || | |
334 | (imgp->ip_flags & IMGPF_INTERPRET) != 0) { | |
335 | return (-1); | |
336 | } | |
337 | ||
338 | ||
339 | imgp->ip_flags |= IMGPF_INTERPRET; | |
340 | ||
341 | /* Check to see if SUGID scripts are permitted. If they aren't then | |
342 | * clear the SUGID bits. | |
343 | * imgp->ip_vattr is known to be valid. | |
344 | */ | |
345 | if (sugid_scripts == 0) { | |
346 | imgp->ip_origvattr->va_mode &= ~(VSUID | VSGID); | |
347 | } | |
348 | ||
349 | /* Find the nominal end of the interpreter line */ | |
350 | for( ihp = &vdata[2]; *ihp != '\n' && *ihp != '#'; ihp++) { | |
351 | if (ihp >= &vdata[IMG_SHSIZE]) | |
352 | return (ENOEXEC); | |
353 | } | |
354 | ||
355 | line_endp = ihp; | |
356 | ihp = &vdata[2]; | |
357 | /* Skip over leading spaces - until the interpreter name */ | |
358 | while ( ihp < line_endp && ((*ihp == ' ') || (*ihp == '\t'))) | |
359 | ihp++; | |
360 | ||
361 | /* | |
362 | * Find the last non-whitespace character before the end of line or | |
363 | * the beginning of a comment; this is our new end of line. | |
364 | */ | |
365 | for (;line_endp > ihp && ((*line_endp == ' ') || (*line_endp == '\t')); line_endp--) | |
366 | continue; | |
367 | ||
368 | /* Empty? */ | |
369 | if (line_endp == ihp) | |
370 | return (ENOEXEC); | |
371 | ||
372 | /* copy the interpreter name */ | |
373 | interp = imgp->ip_interp_name; | |
374 | while ((ihp < line_endp) && (*ihp != ' ') && (*ihp != '\t')) | |
375 | *interp++ = *ihp++; | |
376 | *interp = '\0'; | |
377 | ||
378 | exec_save_path(imgp, CAST_USER_ADDR_T(imgp->ip_interp_name), | |
379 | UIO_SYSSPACE32); | |
380 | ||
381 | ihp = &vdata[2]; | |
382 | while (ihp < line_endp) { | |
383 | /* Skip leading whitespace before each argument */ | |
384 | while ((*ihp == ' ') || (*ihp == '\t')) | |
385 | ihp++; | |
386 | ||
387 | if (ihp >= line_endp) | |
388 | break; | |
389 | ||
390 | /* We have an argument; copy it */ | |
391 | while ((ihp < line_endp) && (*ihp != ' ') && (*ihp != '\t')) { | |
392 | *imgp->ip_strendp++ = *ihp++; | |
393 | imgp->ip_strspace--; | |
394 | } | |
395 | *imgp->ip_strendp++ = 0; | |
396 | imgp->ip_strspace--; | |
397 | imgp->ip_argc++; | |
398 | } | |
399 | ||
400 | return (-3); | |
401 | } | |
402 | ||
403 | ||
404 | ||
405 | /* | |
406 | * exec_fat_imgact | |
407 | * | |
408 | * Image activator for fat 1.0 binaries. If the binary is fat, then we | |
409 | * need to select an image from it internally, and make that the image | |
410 | * we are going to attempt to execute. At present, this consists of | |
411 | * reloading the first page for the image with a first page from the | |
412 | * offset location indicated by the fat header. | |
413 | * | |
414 | * Important: This image activator is byte order neutral. | |
415 | * | |
416 | * Note: If we find an encapsulated binary, we make no assertions | |
417 | * about its validity; instead, we leave that up to a rescan | |
418 | * for an activator to claim it, and, if it is claimed by one, | |
419 | * that activator is responsible for determining validity. | |
420 | */ | |
421 | static int | |
422 | exec_fat_imgact(struct image_params *imgp) | |
423 | { | |
424 | struct proc *p = vfs_context_proc(imgp->ip_vfs_context); | |
21362eb3 | 425 | kauth_cred_t cred = p->p_ucred; |
91447636 A |
426 | struct fat_header *fat_header = (struct fat_header *)imgp->ip_vdata; |
427 | struct fat_arch fat_arch; | |
428 | int resid, error; | |
429 | load_return_t lret; | |
430 | ||
431 | /* Make sure it's a fat binary */ | |
432 | if ((fat_header->magic != FAT_MAGIC) && | |
433 | (fat_header->magic != FAT_CIGAM)) { | |
434 | error = -1; | |
435 | goto bad; | |
436 | } | |
437 | ||
438 | /* Look up our preferred architecture in the fat file. */ | |
439 | lret = fatfile_getarch_affinity(imgp->ip_vp, | |
440 | (vm_offset_t)fat_header, | |
441 | &fat_arch, | |
442 | (p->p_flag & P_AFFINITY)); | |
443 | if (lret != LOAD_SUCCESS) { | |
444 | error = load_return_to_errno(lret); | |
445 | goto bad; | |
446 | } | |
447 | ||
448 | /* Read the Mach-O header out of it */ | |
449 | error = vn_rdwr(UIO_READ, imgp->ip_vp, imgp->ip_vdata, | |
450 | PAGE_SIZE, fat_arch.offset, | |
451 | UIO_SYSSPACE32, (IO_UNIT|IO_NODELOCKED), | |
452 | cred, &resid, p); | |
453 | if (error) { | |
454 | goto bad; | |
455 | } | |
456 | ||
457 | /* Did we read a complete header? */ | |
458 | if (resid) { | |
459 | error = EBADEXEC; | |
460 | goto bad; | |
461 | } | |
462 | ||
463 | /* Success. Indicate we have identified an encapsulated binary */ | |
464 | error = -2; | |
465 | imgp->ip_arch_offset = (user_size_t)fat_arch.offset; | |
466 | imgp->ip_arch_size = (user_size_t)fat_arch.size; | |
467 | ||
468 | bad: | |
469 | return (error); | |
470 | } | |
471 | ||
472 | /* | |
473 | * exec_mach_imgact | |
474 | * | |
475 | * Image activator for mach-o 1.0 binaries. | |
476 | * | |
477 | * Important: This image activator is NOT byte order neutral. | |
478 | */ | |
479 | static int | |
480 | exec_mach_imgact(struct image_params *imgp) | |
481 | { | |
482 | struct mach_header *mach_header = (struct mach_header *)imgp->ip_vdata; | |
483 | kauth_cred_t cred = vfs_context_ucred(imgp->ip_vfs_context); | |
484 | struct proc *p = vfs_context_proc(imgp->ip_vfs_context); | |
485 | int error = 0; | |
486 | int vfexec = 0; | |
487 | task_t task; | |
488 | task_t new_task; | |
489 | thread_t thread; | |
1c79356b | 490 | struct uthread *uthread; |
91447636 | 491 | vm_map_t old_map = VM_MAP_NULL; |
0b4e3aa0 | 492 | vm_map_t map; |
55e303ae | 493 | boolean_t clean_regions = FALSE; |
21362eb3 | 494 | shared_region_mapping_t initial_region = NULL; |
91447636 A |
495 | load_return_t lret; |
496 | load_result_t load_result; | |
497 | ||
498 | /* | |
499 | * make sure it's a Mach-O 1.0 or Mach-O 2.0 binary; the difference | |
500 | * is a reserved field on the end, so for the most part, we can | |
501 | * treat them as if they were identical. | |
502 | */ | |
503 | if ((mach_header->magic != MH_MAGIC) && | |
504 | (mach_header->magic != MH_MAGIC_64)) { | |
505 | error = -1; | |
506 | goto bad; | |
507 | } | |
508 | ||
509 | task = current_task(); | |
510 | thread = current_thread(); | |
511 | uthread = get_bsdthread_info(thread); | |
512 | ||
513 | if (uthread->uu_flag & UT_VFORK) | |
514 | vfexec = 1; /* Mark in exec */ | |
515 | ||
516 | if ((mach_header->cputype & CPU_ARCH_ABI64) == CPU_ARCH_ABI64) | |
517 | imgp->ip_flags |= IMGPF_IS_64BIT; | |
518 | ||
519 | if (!grade_binary(mach_header->cputype, mach_header->cpusubtype)) { | |
520 | error = EBADARCH; | |
521 | goto bad; | |
522 | } | |
523 | ||
524 | /* | |
525 | * Copy in arguments/environment from the old process, if the | |
526 | * vector is non-NULL (i.e. exec is not being called from | |
527 | * load_init_program(), as a special case, at system startup). | |
528 | */ | |
529 | if (imgp->ip_user_argv != 0LL) { | |
530 | error = exec_extract_strings(imgp); | |
531 | if (error) | |
532 | goto bad; | |
533 | } | |
534 | ||
535 | /* | |
536 | * Hack for binary compatability; put three NULs on the end of the | |
537 | * string area, and round it up to the next word boundary. This | |
538 | * ensures padding with NULs to the boundary. | |
539 | */ | |
540 | imgp->ip_strendp[0] = 0; | |
541 | imgp->ip_strendp[1] = 0; | |
542 | imgp->ip_strendp[2] = 0; | |
543 | imgp->ip_strendp += (((imgp->ip_strendp - imgp->ip_strings) + NBPW-1) & ~(NBPW-1)); | |
544 | ||
545 | ||
546 | if (vfexec) { | |
547 | kern_return_t result; | |
548 | ||
21362eb3 | 549 | result = task_create_internal(task, FALSE, &new_task); |
91447636 A |
550 | if (result != KERN_SUCCESS) |
551 | printf("execve: task_create failed. Code: 0x%x\n", result); | |
552 | p->task = new_task; | |
553 | set_bsdtask_info(new_task, p); | |
554 | if (p->p_nice != 0) | |
555 | resetpriority(p); | |
556 | map = get_task_map(new_task); | |
557 | result = thread_create(new_task, &imgp->ip_vfork_thread); | |
558 | if (result != KERN_SUCCESS) | |
559 | printf("execve: thread_create failed. Code: 0x%x\n", result); | |
560 | /* reset local idea of task, thread, uthread */ | |
561 | task = new_task; | |
562 | thread = imgp->ip_vfork_thread; | |
563 | uthread = get_bsdthread_info(thread); | |
564 | } else { | |
565 | map = VM_MAP_NULL; | |
566 | } | |
567 | ||
568 | /* | |
569 | * We set these flags here; this is OK, since if we fail after | |
570 | * this point, we have already destroyed the parent process anyway. | |
571 | */ | |
572 | if (imgp->ip_flags & IMGPF_IS_64BIT) { | |
573 | task_set_64bit(task, TRUE); | |
574 | p->p_flag |= P_LP64; | |
575 | } else { | |
576 | task_set_64bit(task, FALSE); | |
577 | p->p_flag &= ~P_LP64; | |
578 | } | |
579 | ||
580 | /* | |
581 | * Load the Mach-O file. | |
582 | */ | |
583 | /* LP64 - remove following "if" statement after osfmk/vm/task_working_set.c */ | |
584 | if((imgp->ip_flags & IMGPF_IS_64BIT) == 0) | |
585 | if(imgp->ip_tws_cache_name) { | |
586 | tws_handle_startup_file(task, kauth_cred_getuid(cred), | |
587 | imgp->ip_tws_cache_name, imgp->ip_vp, &clean_regions); | |
588 | } | |
589 | ||
590 | vm_get_shared_region(task, &initial_region); | |
591 | ||
21362eb3 | 592 | |
91447636 A |
593 | /* |
594 | * NOTE: An error after this point indicates we have potentially | |
595 | * destroyed or overwrote some process state while attempting an | |
596 | * execve() following a vfork(), which is an unrecoverable condition. | |
597 | */ | |
598 | ||
599 | /* | |
600 | * We reset the task to 64-bit (or not) here. It may have picked up | |
601 | * a new map, and we need that to reflect its true 64-bit nature. | |
602 | */ | |
603 | task_set_64bit(task, | |
604 | ((imgp->ip_flags & IMGPF_IS_64BIT) == IMGPF_IS_64BIT)); | |
605 | ||
606 | /* | |
607 | * Actually load the image file we previously decided to load. | |
608 | */ | |
609 | lret = load_machfile(imgp, mach_header, thread, map, clean_regions, &load_result); | |
610 | ||
611 | if (lret != LOAD_SUCCESS) { | |
612 | error = load_return_to_errno(lret); | |
613 | goto badtoolate; | |
614 | } | |
615 | ||
616 | /* load_machfile() maps the vnode */ | |
617 | (void)ubc_map(imgp->ip_vp, PROT_EXEC); | |
618 | ||
619 | /* | |
620 | * deal with set[ug]id. | |
621 | */ | |
622 | error = exec_handle_sugid(imgp); | |
623 | ||
624 | KNOTE(&p->p_klist, NOTE_EXEC); | |
625 | ||
626 | if (!vfexec && (p->p_flag & P_TRACED)) | |
627 | psignal(p, SIGTRAP); | |
628 | ||
629 | if (error) { | |
630 | goto badtoolate; | |
631 | } | |
632 | vnode_put(imgp->ip_vp); | |
633 | imgp->ip_vp = NULL; | |
634 | ||
635 | if (load_result.unixproc && | |
636 | create_unix_stack(get_task_map(task), | |
637 | load_result.user_stack, load_result.customstack, p)) { | |
638 | error = load_return_to_errno(LOAD_NOSPACE); | |
639 | goto badtoolate; | |
640 | } | |
641 | ||
642 | if (vfexec) { | |
21362eb3 | 643 | uthread->uu_ar0 = (void *)get_user_regs(thread); |
91447636 A |
644 | old_map = vm_map_switch(get_task_map(task)); |
645 | } | |
646 | ||
647 | if (load_result.unixproc) { | |
648 | user_addr_t ap; | |
649 | ||
650 | /* | |
651 | * Copy the strings area out into the new process address | |
652 | * space. | |
653 | */ | |
654 | ap = p->user_stack; | |
655 | error = exec_copyout_strings(imgp, &ap); | |
656 | if (error) { | |
657 | if (vfexec) | |
658 | vm_map_switch(old_map); | |
659 | goto badtoolate; | |
660 | } | |
661 | /* Set the stack */ | |
662 | thread_setuserstack(thread, ap); | |
663 | } | |
664 | ||
665 | if (load_result.dynlinker) { | |
666 | uint64_t ap; | |
667 | ||
668 | /* Adjust the stack */ | |
669 | if (imgp->ip_flags & IMGPF_IS_64BIT) { | |
670 | ap = thread_adjuserstack(thread, -8); | |
21362eb3 | 671 | (void)copyoutptr(load_result.mach_header, ap, 8); |
91447636 A |
672 | } else { |
673 | ap = thread_adjuserstack(thread, -4); | |
21362eb3 | 674 | (void)suword(ap, load_result.mach_header); |
91447636 A |
675 | } |
676 | } | |
677 | ||
678 | if (vfexec) { | |
679 | vm_map_switch(old_map); | |
680 | } | |
681 | /* Set the entry point */ | |
682 | thread_setentrypoint(thread, load_result.entry_point); | |
683 | ||
684 | /* Stop profiling */ | |
685 | stopprofclock(p); | |
686 | ||
687 | /* | |
688 | * Reset signal state. | |
689 | */ | |
690 | execsigs(p, thread); | |
691 | ||
692 | /* | |
693 | * Close file descriptors | |
694 | * which specify close-on-exec. | |
695 | */ | |
696 | fdexec(p); | |
697 | ||
698 | /* | |
699 | * need to cancel async IO requests that can be cancelled and wait for those | |
700 | * already active. MAY BLOCK! | |
701 | */ | |
702 | _aio_exec( p ); | |
703 | ||
704 | /* FIXME: Till vmspace inherit is fixed: */ | |
705 | if (!vfexec && p->vm_shm) | |
706 | shmexec(p); | |
707 | /* Clean up the semaphores */ | |
708 | semexit(p); | |
709 | ||
710 | /* | |
711 | * Remember file name for accounting. | |
712 | */ | |
713 | p->p_acflag &= ~AFORK; | |
714 | /* If the translated name isn't NULL, then we want to use | |
715 | * that translated name as the name we show as the "real" name. | |
716 | * Otherwise, use the name passed into exec. | |
717 | */ | |
718 | if (0 != imgp->ip_p_comm[0]) { | |
719 | bcopy((caddr_t)imgp->ip_p_comm, (caddr_t)p->p_comm, | |
720 | sizeof(p->p_comm)); | |
721 | } else { | |
722 | if (imgp->ip_ndp->ni_cnd.cn_namelen > MAXCOMLEN) | |
723 | imgp->ip_ndp->ni_cnd.cn_namelen = MAXCOMLEN; | |
724 | bcopy((caddr_t)imgp->ip_ndp->ni_cnd.cn_nameptr, (caddr_t)p->p_comm, | |
725 | (unsigned)imgp->ip_ndp->ni_cnd.cn_namelen); | |
726 | p->p_comm[imgp->ip_ndp->ni_cnd.cn_namelen] = '\0'; | |
727 | } | |
55e303ae | 728 | |
21362eb3 A |
729 | { |
730 | /* This is for kdebug */ | |
731 | long dbg_arg1, dbg_arg2, dbg_arg3, dbg_arg4; | |
732 | ||
733 | /* Collect the pathname for tracing */ | |
734 | kdbg_trace_string(p, &dbg_arg1, &dbg_arg2, &dbg_arg3, &dbg_arg4); | |
735 | ||
736 | ||
737 | ||
738 | if (vfexec) | |
739 | { | |
740 | KERNEL_DEBUG_CONSTANT1((TRACEDBG_CODE(DBG_TRACE_DATA, 2)) | DBG_FUNC_NONE, | |
741 | p->p_pid ,0,0,0, (unsigned int)thread); | |
742 | KERNEL_DEBUG_CONSTANT1((TRACEDBG_CODE(DBG_TRACE_STRING, 2)) | DBG_FUNC_NONE, | |
743 | dbg_arg1, dbg_arg2, dbg_arg3, dbg_arg4, (unsigned int)thread); | |
744 | } | |
745 | else | |
746 | { | |
747 | KERNEL_DEBUG_CONSTANT((TRACEDBG_CODE(DBG_TRACE_DATA, 2)) | DBG_FUNC_NONE, | |
748 | p->p_pid ,0,0,0,0); | |
749 | KERNEL_DEBUG_CONSTANT((TRACEDBG_CODE(DBG_TRACE_STRING, 2)) | DBG_FUNC_NONE, | |
750 | dbg_arg1, dbg_arg2, dbg_arg3, dbg_arg4, 0); | |
751 | } | |
91447636 A |
752 | } |
753 | ||
21362eb3 | 754 | p->p_flag &= ~P_CLASSIC; |
91447636 A |
755 | |
756 | /* | |
757 | * mark as execed, wakeup the process that vforked (if any) and tell | |
758 | * it that it now has it's own resources back | |
759 | */ | |
760 | p->p_flag |= P_EXEC; | |
761 | if (p->p_pptr && (p->p_flag & P_PPWAIT)) { | |
762 | p->p_flag &= ~P_PPWAIT; | |
763 | wakeup((caddr_t)p->p_pptr); | |
764 | } | |
765 | ||
766 | if (vfexec && (p->p_flag & P_TRACED)) { | |
767 | psignal_vfork(p, new_task, thread, SIGTRAP); | |
768 | } | |
769 | ||
770 | badtoolate: | |
771 | if (vfexec) { | |
772 | task_deallocate(new_task); | |
773 | thread_deallocate(thread); | |
774 | if (error) | |
775 | error = 0; | |
776 | } | |
777 | ||
778 | bad: | |
779 | return(error); | |
780 | } | |
781 | ||
782 | ||
783 | ||
784 | ||
785 | /* | |
786 | * Our image activator table; this is the table of the image types we are | |
787 | * capable of loading. We list them in order of preference to ensure the | |
788 | * fastest image load speed. | |
789 | * | |
790 | * XXX hardcoded, for now; should use linker sets | |
791 | */ | |
792 | struct execsw { | |
793 | int (*ex_imgact)(struct image_params *); | |
794 | const char *ex_name; | |
795 | } execsw[] = { | |
796 | { exec_mach_imgact, "Mach-o Binary" }, | |
797 | { exec_fat_imgact, "Fat Binary" }, | |
798 | { exec_shell_imgact, "Interpreter Script" }, | |
799 | { NULL, NULL} | |
800 | }; | |
801 | ||
802 | ||
803 | /* | |
804 | * TODO: Dynamic linker header address on stack is copied via suword() | |
805 | */ | |
806 | /* ARGSUSED */ | |
807 | int | |
808 | execve(struct proc *p, struct execve_args *uap, register_t *retval) | |
809 | { | |
21362eb3 | 810 | kauth_cred_t cred = p->p_ucred; |
91447636 A |
811 | struct image_params image_params, *imgp; |
812 | struct vnode_attr va; | |
813 | struct vnode_attr origva; | |
814 | struct nameidata nd; | |
815 | struct uthread *uthread; | |
816 | int i; | |
1c79356b | 817 | int resid, error; |
0b4e3aa0 | 818 | task_t task; |
1c79356b | 819 | int numthreads; |
0b4e3aa0 | 820 | int vfexec=0; |
91447636 | 821 | int once = 1; /* save SGUID-ness for interpreted files */ |
21362eb3 | 822 | char alt_p_comm[sizeof(p->p_comm)] = {0}; /* for Classic */ |
91447636 A |
823 | int is_64 = IS_64BIT_PROCESS(p); |
824 | int seg = (is_64 ? UIO_USERSPACE64 : UIO_USERSPACE32); | |
825 | struct vfs_context context; | |
826 | ||
827 | context.vc_proc = p; | |
21362eb3 | 828 | context.vc_ucred = p->p_ucred; /* XXX must NOT be kauth_cred_get() */ |
91447636 A |
829 | |
830 | ||
831 | imgp = &image_params; | |
832 | ||
833 | /* Initialize the common data in the image_params structure */ | |
834 | bzero(imgp, sizeof(*imgp)); | |
835 | imgp->ip_user_fname = uap->fname; | |
836 | imgp->ip_user_argv = uap->argp; | |
837 | imgp->ip_user_envv = uap->envp; | |
838 | imgp->ip_vattr = &va; | |
839 | imgp->ip_origvattr = &origva; | |
840 | imgp->ip_vfs_context = &context; | |
841 | imgp->ip_flags = (is_64 ? IMGPF_WAS_64BIT : IMGPF_NONE); | |
842 | imgp->ip_tws_cache_name = NULL; | |
21362eb3 | 843 | imgp->ip_p_comm = alt_p_comm; /* for Classic */ |
1c79356b | 844 | |
91447636 | 845 | /* |
55e303ae A |
846 | * XXXAUDIT: Currently, we only audit the pathname of the binary. |
847 | * There may also be poor interaction with dyld. | |
848 | */ | |
849 | ||
0b4e3aa0 | 850 | task = current_task(); |
91447636 | 851 | uthread = get_bsdthread_info(current_thread()); |
1c79356b | 852 | |
91447636 | 853 | if (uthread->uu_flag & UT_VFORK) { |
0b4e3aa0 A |
854 | vfexec = 1; /* Mark in exec */ |
855 | } else { | |
856 | if (task != kernel_task) { | |
857 | numthreads = get_task_numacts(task); | |
21362eb3 | 858 | if (numthreads <= 0 ) |
0b4e3aa0 A |
859 | return(EINVAL); |
860 | if (numthreads > 1) { | |
91447636 | 861 | return(ENOTSUP); |
0b4e3aa0 | 862 | } |
1c79356b A |
863 | } |
864 | } | |
865 | ||
91447636 | 866 | error = execargs_alloc(imgp); |
21362eb3 | 867 | if (error) |
765c9de3 | 868 | return(error); |
21362eb3 | 869 | |
55e303ae A |
870 | /* |
871 | * XXXAUDIT: Note: the double copyin introduces an audit | |
872 | * race. To correct this race, we must use a single | |
91447636 A |
873 | * copyin(), e.g. by passing a flag to namei to indicate an |
874 | * external path buffer is being used. | |
55e303ae | 875 | */ |
91447636 | 876 | error = exec_save_path(imgp, uap->fname, seg); |
55e303ae | 877 | if (error) { |
91447636 | 878 | execargs_free(imgp); |
55e303ae A |
879 | return(error); |
880 | } | |
91447636 | 881 | |
1c79356b | 882 | /* |
55e303ae | 883 | * No app profiles under chroot |
1c79356b | 884 | */ |
91447636 | 885 | if((p->p_fd->fd_rdir == NULLVP) && (app_profile != 0)) { |
9bccf70c A |
886 | |
887 | /* grab the name of the file out of its path */ | |
888 | /* we will need this for lookup within the */ | |
889 | /* name file */ | |
91447636 A |
890 | /* Scan backwards for the first '/' or start of string */ |
891 | imgp->ip_tws_cache_name = imgp->ip_strendp; | |
892 | while (imgp->ip_tws_cache_name[0] != '/') { | |
893 | if(imgp->ip_tws_cache_name == imgp->ip_strings) { | |
894 | imgp->ip_tws_cache_name--; | |
9bccf70c A |
895 | break; |
896 | } | |
91447636 | 897 | imgp->ip_tws_cache_name--; |
9bccf70c | 898 | } |
91447636 | 899 | imgp->ip_tws_cache_name++; |
9bccf70c | 900 | } |
91447636 A |
901 | NDINIT(&nd, LOOKUP, FOLLOW | LOCKLEAF | AUDITVNPATH1, |
902 | seg, uap->fname, imgp->ip_vfs_context); | |
55e303ae | 903 | |
91447636 | 904 | again: |
55e303ae A |
905 | error = namei(&nd); |
906 | if (error) | |
1c79356b | 907 | goto bad; |
91447636 A |
908 | imgp->ip_ndp = &nd; /* successful namei(); call nameidone() later */ |
909 | imgp->ip_vp = nd.ni_vp; /* if set, need to vnode_put() at some point */ | |
1c79356b | 910 | |
91447636 A |
911 | error = exec_check_permissions(imgp); |
912 | if (error) | |
1c79356b | 913 | goto bad; |
1c79356b | 914 | |
91447636 A |
915 | /* Copy; avoid invocation of an interpreter overwriting the original */ |
916 | if (once) { | |
917 | once = 0; | |
918 | origva = va; | |
919 | } | |
1c79356b | 920 | |
91447636 A |
921 | error = vn_rdwr(UIO_READ, imgp->ip_vp, imgp->ip_vdata, PAGE_SIZE, 0, |
922 | UIO_SYSSPACE32, IO_NODELOCKED, cred, &resid, p); | |
1c79356b A |
923 | if (error) |
924 | goto bad; | |
91447636 A |
925 | |
926 | encapsulated_binary: | |
927 | error = -1; | |
928 | for(i = 0; error == -1 && execsw[i].ex_imgact != NULL; i++) { | |
1c79356b | 929 | |
91447636 | 930 | error = (*execsw[i].ex_imgact)(imgp); |
1c79356b | 931 | |
91447636 A |
932 | switch (error) { |
933 | /* case -1: not claimed: continue */ | |
934 | case -2: /* Encapsulated binary */ | |
935 | goto encapsulated_binary; | |
1c79356b | 936 | |
91447636 A |
937 | case -3: /* Interpreter */ |
938 | vnode_put(imgp->ip_vp); | |
939 | imgp->ip_vp = NULL; /* already put */ | |
940 | nd.ni_cnd.cn_nameiop = LOOKUP; | |
941 | nd.ni_cnd.cn_flags = (nd.ni_cnd.cn_flags & HASBUF) | | |
942 | (FOLLOW | LOCKLEAF); | |
1c79356b | 943 | |
1c79356b | 944 | |
91447636 A |
945 | nd.ni_segflg = UIO_SYSSPACE32; |
946 | nd.ni_dirp = CAST_USER_ADDR_T(imgp->ip_interp_name); | |
947 | goto again; | |
948 | ||
949 | default: | |
950 | break; | |
951 | } | |
952 | } | |
953 | ||
954 | /* call out to allow 3rd party notification of exec. | |
955 | * Ignore result of kauth_authorize_fileop call. | |
956 | */ | |
957 | if (error == 0 && kauth_authorize_fileop_has_listeners()) { | |
958 | kauth_authorize_fileop(vfs_context_ucred(&context), KAUTH_FILEOP_EXEC, | |
959 | (uintptr_t)nd.ni_vp, 0); | |
960 | } | |
961 | ||
962 | /* Image not claimed by any activator? */ | |
963 | if (error == -1) | |
1c79356b | 964 | error = ENOEXEC; |
91447636 A |
965 | |
966 | bad: | |
967 | if (imgp->ip_ndp) | |
968 | nameidone(imgp->ip_ndp); | |
969 | if (imgp->ip_vp) | |
970 | vnode_put(imgp->ip_vp); | |
971 | if (imgp->ip_strings) | |
972 | execargs_free(imgp); | |
973 | if (!error && vfexec) { | |
974 | vfork_return(current_thread(), p->p_pptr, p, retval); | |
975 | (void)thread_resume(imgp->ip_vfork_thread); | |
976 | return(0); | |
1c79356b | 977 | } |
91447636 A |
978 | return(error); |
979 | } | |
980 | ||
981 | ||
982 | static int | |
983 | copyinptr(user_addr_t froma, user_addr_t *toptr, int ptr_size) | |
984 | { | |
985 | int error; | |
986 | ||
987 | if (ptr_size == 4) { | |
988 | /* 64 bit value containing 32 bit address */ | |
989 | unsigned int i; | |
990 | ||
991 | error = copyin(froma, &i, 4); | |
992 | *toptr = CAST_USER_ADDR_T(i); /* SAFE */ | |
1c79356b | 993 | } else { |
91447636 A |
994 | error = copyin(froma, toptr, 8); |
995 | } | |
996 | return (error); | |
997 | } | |
a3d08fcd | 998 | |
1c79356b | 999 | |
91447636 A |
1000 | static int |
1001 | copyoutptr(user_addr_t ua, user_addr_t ptr, int ptr_size) | |
1002 | { | |
1003 | int error; | |
1c79356b | 1004 | |
91447636 A |
1005 | if (ptr_size == 4) { |
1006 | /* 64 bit value containing 32 bit address */ | |
1007 | unsigned int i = CAST_DOWN(unsigned int,ua); /* SAFE */ | |
1008 | ||
1009 | error = copyout(&i, ptr, 4); | |
1010 | } else { | |
1011 | error = copyout(&ua, ptr, 8); | |
1c79356b | 1012 | } |
91447636 A |
1013 | return (error); |
1014 | } | |
1015 | ||
1016 | ||
1017 | /* | |
1018 | * exec_copyout_strings | |
1019 | * | |
1020 | * Copy out the strings segment to user space. The strings segment is put | |
1021 | * on a preinitialized stack frame. | |
1022 | * | |
1023 | * Parameters: struct image_params * the image parameter block | |
1024 | * int * a pointer to the stack offset variable | |
1025 | * | |
1026 | * Returns: 0 Success | |
1027 | * !0 Faiure: errno | |
1028 | * | |
1029 | * Implicit returns: | |
1030 | * (*stackp) The stack offset, modified | |
1031 | * | |
1032 | * Note: The strings segment layout is backward, from the beginning | |
1033 | * of the top of the stack to consume the minimal amount of | |
1034 | * space possible; the returned stack pointer points to the | |
1035 | * end of the area consumed (stacks grow upward). | |
1036 | * | |
1037 | * argc is an int; arg[i] are pointers; env[i] are pointers; | |
1038 | * exec_path is a pointer; the 0's are (void *)NULL's | |
1039 | * | |
1040 | * The stack frame layout is: | |
1041 | * | |
1042 | * +-------------+ | |
1043 | * sp-> | argc | | |
1044 | * +-------------+ | |
1045 | * | arg[0] | | |
1046 | * +-------------+ | |
1047 | * : | |
1048 | * : | |
1049 | * +-------------+ | |
1050 | * | arg[argc-1] | | |
1051 | * +-------------+ | |
1052 | * | 0 | | |
1053 | * +-------------+ | |
1054 | * | env[0] | | |
1055 | * +-------------+ | |
1056 | * : | |
1057 | * : | |
1058 | * +-------------+ | |
1059 | * | env[n] | | |
1060 | * +-------------+ | |
1061 | * | 0 | | |
1062 | * +-------------+ | |
1063 | * | exec_path | In MacOS X PR2 Beaker2E the path passed to exec() is | |
1064 | * +-------------+ passed on the stack just after the trailing 0 of the | |
1065 | * | 0 | the envp[] array as a pointer to a string. | |
1066 | * +-------------+ | |
1067 | * | PATH AREA | | |
1068 | * +-------------+ | |
1069 | * | STRING AREA | | |
1070 | * : | |
1071 | * : | |
1072 | * | | <- p->user_stack | |
1073 | * +-------------+ | |
1074 | * | |
1075 | * Although technically a part of the STRING AREA, we treat the PATH AREA as | |
1076 | * a separate entity. This allows us to align the beginning of the PATH AREA | |
1077 | * to a pointer boundary so that the exec_path, env[i], and argv[i] pointers | |
1078 | * which preceed it on the stack are properly aligned. | |
1079 | * | |
1080 | * TODO: argc copied with suword(), which takes a 64 bit address | |
1081 | */ | |
1082 | static int | |
1083 | exec_copyout_strings(struct image_params *imgp, user_addr_t *stackp) | |
1084 | { | |
1085 | struct proc *p = vfs_context_proc(imgp->ip_vfs_context); | |
1086 | int ptr_size = (imgp->ip_flags & IMGPF_IS_64BIT) ? 8 : 4; | |
1087 | char *argv = imgp->ip_argv; /* modifiable copy of argv */ | |
1088 | user_addr_t string_area; /* *argv[], *env[] */ | |
1089 | user_addr_t path_area; /* package launch path */ | |
1090 | user_addr_t ptr_area; /* argv[], env[], exec_path */ | |
1091 | user_addr_t stack; | |
1092 | int stringc = imgp->ip_argc + imgp->ip_envc; | |
1093 | int len; | |
1094 | int error; | |
1095 | int strspace; | |
1096 | ||
1097 | stack = *stackp; | |
1098 | ||
1099 | /* | |
1100 | * Set up pointers to the beginning of the string area, the beginning | |
1101 | * of the path area, and the beginning of the pointer area (actually, | |
1102 | * the location of argc, an int, which may be smaller than a pointer, | |
1103 | * but we use ptr_size worth of space for it, for alignment). | |
1104 | */ | |
1105 | string_area = stack - (((imgp->ip_strendp - imgp->ip_strings) + ptr_size-1) & ~(ptr_size-1)) - ptr_size; | |
21362eb3 A |
1106 | path_area = string_area - (((imgp->ip_argv - imgp->ip_strings) + ptr_size-1) & ~(ptr_size-1)); |
1107 | ptr_area = path_area - ((imgp->ip_argc + imgp->ip_envc + 4) * ptr_size) - ptr_size /*argc*/; | |
91447636 A |
1108 | |
1109 | /* Return the initial stack address: the location of argc */ | |
1110 | *stackp = ptr_area; | |
1c79356b A |
1111 | |
1112 | /* | |
91447636 A |
1113 | * Record the size of the arguments area so that sysctl_procargs() |
1114 | * can return the argument area without having to parse the arguments. | |
1c79356b | 1115 | */ |
91447636 A |
1116 | p->p_argc = imgp->ip_argc; |
1117 | p->p_argslen = (int)(stack - path_area); | |
1118 | ||
1119 | ||
1c79356b A |
1120 | /* |
1121 | * Support for new app package launching for Mac OS X allocates | |
91447636 A |
1122 | * the "path" at the begining of the imgp->ip_strings buffer. |
1123 | * copy it just before the string area. | |
1c79356b | 1124 | */ |
91447636 A |
1125 | len = 0; |
1126 | error = copyoutstr(imgp->ip_strings, path_area, | |
21362eb3 | 1127 | (unsigned)(imgp->ip_argv - imgp->ip_strings), |
91447636 A |
1128 | (size_t *)&len); |
1129 | if (error) | |
1130 | goto bad; | |
1131 | ||
1132 | ||
1133 | /* Save a NULL pointer below it */ | |
1134 | (void)copyoutptr(0LL, path_area - ptr_size, ptr_size); | |
1135 | ||
1136 | /* Save the pointer to "path" just below it */ | |
1137 | (void)copyoutptr(path_area, path_area - 2*ptr_size, ptr_size); | |
1138 | ||
1c79356b | 1139 | /* |
91447636 A |
1140 | * ptr_size for 2 NULL one each ofter arg[argc -1] and env[n] |
1141 | * ptr_size for argc | |
1142 | * skip over saved path, ptr_size for pointer to path, | |
1143 | * and ptr_size for the NULL after pointer to path. | |
1c79356b | 1144 | */ |
91447636 A |
1145 | |
1146 | /* argc (int32, stored in a ptr_size area) */ | |
1147 | (void)suword(ptr_area, imgp->ip_argc); | |
1148 | ptr_area += sizeof(int); | |
1149 | /* pad to ptr_size, if 64 bit image, to ensure user stack alignment */ | |
1150 | if (imgp->ip_flags & IMGPF_IS_64BIT) { | |
1151 | (void)suword(ptr_area, 0); /* int, not long: ignored */ | |
1152 | ptr_area += sizeof(int); | |
1153 | } | |
1154 | ||
1155 | ||
1c79356b | 1156 | /* |
91447636 A |
1157 | * We use (string_area - path_area) here rather than the more |
1158 | * intuitive (imgp->ip_argv - imgp->ip_strings) because we are | |
1159 | * interested in the length of the PATH_AREA in user space, | |
1160 | * rather than the actual length of the execution path, since | |
1161 | * it includes alignment padding of the PATH_AREA + STRING_AREA | |
1162 | * to a ptr_size boundary. | |
1c79356b | 1163 | */ |
91447636 A |
1164 | strspace = SIZE_IMG_STRSPACE - (string_area - path_area); |
1165 | for (;;) { | |
1166 | if (stringc == imgp->ip_envc) { | |
1167 | /* argv[n] = NULL */ | |
1168 | (void)copyoutptr(0LL, ptr_area, ptr_size); | |
1169 | ptr_area += ptr_size; | |
1170 | } | |
1171 | if (--stringc < 0) | |
1172 | break; | |
1173 | ||
1174 | /* pointer: argv[n]/env[n] */ | |
1175 | (void)copyoutptr(string_area, ptr_area, ptr_size); | |
55e303ae | 1176 | |
91447636 A |
1177 | /* string : argv[n][]/env[n][] */ |
1178 | do { | |
1179 | if (strspace <= 0) { | |
1180 | error = E2BIG; | |
1181 | break; | |
1182 | } | |
1183 | error = copyoutstr(argv, string_area, | |
1184 | (unsigned)strspace, | |
1185 | (size_t *)&len); | |
1186 | string_area += len; | |
1187 | argv += len; | |
1188 | strspace -= len; | |
1189 | } while (error == ENAMETOOLONG); | |
1190 | if (error == EFAULT || error == E2BIG) | |
1191 | break; /* bad stack - user's problem */ | |
1192 | ptr_area += ptr_size; | |
1193 | } | |
1194 | /* env[n] = NULL */ | |
1195 | (void)copyoutptr(0LL, ptr_area, ptr_size); | |
1196 | ||
1197 | bad: | |
1198 | return(error); | |
1199 | } | |
1200 | ||
1201 | ||
1202 | /* | |
1203 | * exec_extract_strings | |
1204 | * | |
1205 | * Copy arguments and environment from user space into work area; we may | |
1206 | * have already copied some early arguments into the work area, and if | |
1207 | * so, any arguments opied in are appended to those already there. | |
1208 | * | |
1209 | * Parameters: struct image_params * the image parameter block | |
1210 | * | |
1211 | * Returns: 0 Success | |
1212 | * !0 Failure: errno | |
1213 | * | |
1214 | * Implicit returns; | |
1215 | * (imgp->ip_argc) Count of arguments, updated | |
1216 | * (imgp->ip_envc) Count of environment strings, updated | |
1217 | * | |
1218 | * | |
1219 | * Notes: The argument and environment vectors are user space pointers | |
1220 | * to arrays of user space pointers. | |
1221 | */ | |
1222 | static int | |
1223 | exec_extract_strings(struct image_params *imgp) | |
1224 | { | |
1225 | int error = 0; | |
1226 | struct proc *p = vfs_context_proc(imgp->ip_vfs_context); | |
1227 | int seg = (IS_64BIT_PROCESS(p) ? UIO_USERSPACE64 : UIO_USERSPACE32); | |
1228 | int ptr_size = (imgp->ip_flags & IMGPF_WAS_64BIT) ? 8 : 4; | |
1229 | user_addr_t argv = imgp->ip_user_argv; | |
1230 | user_addr_t envv = imgp->ip_user_envv; | |
1231 | ||
1232 | /* Now, get rest of arguments */ | |
1c79356b A |
1233 | |
1234 | /* | |
91447636 A |
1235 | * If we are running an interpreter, replace the av[0] that was |
1236 | * passed to execve() with the fully qualified path name that was | |
1237 | * passed to execve() for interpreters which do not use the PATH | |
1238 | * to locate their script arguments. | |
1c79356b | 1239 | */ |
91447636 A |
1240 | if((imgp->ip_flags & IMGPF_INTERPRET) != 0 && argv != 0LL) { |
1241 | user_addr_t arg; | |
1242 | ||
1243 | error = copyinptr(argv, &arg, ptr_size); | |
1244 | if (error) | |
1c79356b | 1245 | goto bad; |
91447636 A |
1246 | if (arg != 0LL && arg != (user_addr_t)-1) { |
1247 | argv += ptr_size; | |
1248 | error = exec_add_string(imgp, imgp->ip_user_fname, seg); | |
1249 | if (error) | |
1250 | goto bad; | |
1251 | imgp->ip_argc++; | |
1c79356b | 1252 | } |
91447636 | 1253 | } |
1c79356b | 1254 | |
91447636 A |
1255 | while (argv != 0LL) { |
1256 | user_addr_t arg; | |
1257 | ||
1258 | error = copyinptr(argv, &arg, ptr_size); | |
1259 | if (error) | |
1c79356b | 1260 | goto bad; |
1c79356b | 1261 | |
91447636 A |
1262 | argv += ptr_size; |
1263 | if (arg == 0LL) { | |
1264 | break; | |
1265 | } else if (arg == (user_addr_t)-1) { | |
1266 | /* Um... why would it be -1? */ | |
1267 | error = EFAULT; | |
1c79356b A |
1268 | goto bad; |
1269 | } | |
91447636 A |
1270 | /* |
1271 | * av[n...] = arg[n] | |
1272 | */ | |
1273 | error = exec_add_string(imgp, arg, seg); | |
1274 | if (error) | |
1275 | goto bad; | |
1276 | imgp->ip_argc++; | |
1277 | } | |
1278 | ||
1279 | /* Now, get the environment */ | |
1280 | while (envv != 0LL) { | |
1281 | user_addr_t env; | |
1282 | ||
1283 | error = copyinptr(envv, &env, ptr_size); | |
1284 | if (error) | |
1285 | goto bad; | |
1c79356b | 1286 | |
91447636 A |
1287 | envv += ptr_size; |
1288 | if (env == 0LL) { | |
1289 | break; | |
1290 | } else if (env == (user_addr_t)-1) { | |
1291 | error = EFAULT; | |
1c79356b A |
1292 | goto bad; |
1293 | } | |
1c79356b | 1294 | /* |
91447636 A |
1295 | * av[n...] = env[n] |
1296 | */ | |
1297 | error = exec_add_string(imgp, env, seg); | |
1298 | if (error) | |
55e303ae | 1299 | goto bad; |
91447636 | 1300 | imgp->ip_envc++; |
55e303ae | 1301 | } |
91447636 A |
1302 | bad: |
1303 | return error; | |
1304 | } | |
55e303ae | 1305 | |
55e303ae | 1306 | |
91447636 | 1307 | #define unix_stack_size(p) (p->p_rlimit[RLIMIT_STACK].rlim_cur) |
55e303ae | 1308 | |
91447636 A |
1309 | static int |
1310 | exec_check_permissions(struct image_params *imgp) | |
1311 | { | |
1312 | struct vnode *vp = imgp->ip_vp; | |
1313 | struct vnode_attr *vap = imgp->ip_vattr; | |
1314 | struct proc *p = vfs_context_proc(imgp->ip_vfs_context); | |
1315 | int error; | |
1316 | kauth_action_t action; | |
55e303ae | 1317 | |
91447636 A |
1318 | /* Only allow execution of regular files */ |
1319 | if (!vnode_isreg(vp)) | |
1320 | return (EACCES); | |
1321 | ||
1322 | /* Get the file attributes that we will be using here and elsewhere */ | |
1323 | VATTR_INIT(vap); | |
1324 | VATTR_WANTED(vap, va_uid); | |
1325 | VATTR_WANTED(vap, va_gid); | |
1326 | VATTR_WANTED(vap, va_mode); | |
1327 | VATTR_WANTED(vap, va_fsid); | |
1328 | VATTR_WANTED(vap, va_fileid); | |
1329 | VATTR_WANTED(vap, va_data_size); | |
1330 | if ((error = vnode_getattr(vp, vap, imgp->ip_vfs_context)) != 0) | |
1331 | return (error); | |
55e303ae | 1332 | |
91447636 A |
1333 | /* |
1334 | * Ensure that at least one execute bit is on - otherwise root | |
1335 | * will always succeed, and we don't want to happen unless the | |
1336 | * file really is executable. | |
1337 | */ | |
1338 | if ((vap->va_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) == 0) | |
1339 | return (EACCES); | |
55e303ae | 1340 | |
91447636 A |
1341 | /* Disallow zero length files */ |
1342 | if (vap->va_data_size == 0) | |
1343 | return (ENOEXEC); | |
55e303ae | 1344 | |
91447636 A |
1345 | imgp->ip_arch_offset = (user_size_t)0; |
1346 | imgp->ip_arch_size = vap->va_data_size; | |
0b4e3aa0 | 1347 | |
91447636 A |
1348 | /* Disable setuid-ness for traced programs or if MNT_NOSUID */ |
1349 | if ((vp->v_mount->mnt_flag & MNT_NOSUID) || (p->p_flag & P_TRACED)) | |
1350 | vap->va_mode &= ~(VSUID | VSGID); | |
1351 | ||
1352 | /* Check for execute permission */ | |
1353 | action = KAUTH_VNODE_EXECUTE; | |
1354 | /* Traced images must also be readable */ | |
1355 | if (p->p_flag & P_TRACED) | |
1356 | action |= KAUTH_VNODE_READ_DATA; | |
1357 | if ((error = vnode_authorize(vp, NULL, action, imgp->ip_vfs_context)) != 0) | |
1358 | return (error); | |
1c79356b | 1359 | |
91447636 A |
1360 | /* Don't let it run if anyone had it open for writing */ |
1361 | if (vp->v_writecount) | |
1362 | return (ETXTBSY); | |
de355530 | 1363 | |
0b4e3aa0 | 1364 | |
91447636 | 1365 | /* XXX May want to indicate to underlying FS that vnode is open */ |
1c79356b | 1366 | |
91447636 A |
1367 | return (error); |
1368 | } | |
1369 | ||
1370 | /* | |
1371 | * exec_handle_sugid | |
1372 | * | |
1373 | * Initially clear the P_SUGID in the process flags; if an SUGID process is | |
1374 | * exec'ing a non-SUGID image, then this is the point of no return. | |
1375 | * | |
1376 | * If the image being activated is SUGI, then replace the credential with a | |
1377 | * copy, disable tracing (unless the tracing process is root), reset the | |
1378 | * mach task port to revoke it, set the P_SUGID bit, | |
1379 | * | |
1380 | * If the saved user and group ID will be changing, then make sure it happens | |
1381 | * to a new credential, rather than a shared one. | |
1382 | * | |
1383 | * Set the security token (this is probably obsolete, given that the token | |
1384 | * should not technically be separate from the credential itself). | |
1385 | * | |
1386 | * Parameters: struct image_params * the image parameter block | |
1387 | * | |
1388 | * Returns: void No failure indication | |
1389 | * | |
1390 | * Implicit returns: | |
1391 | * <process credential> Potentially modified/replaced | |
1392 | * <task port> Potentially revoked | |
1393 | * <process flags> P_SUGID bit potentially modified | |
1394 | * <security token> Potentially modified | |
1395 | */ | |
1396 | static int | |
1397 | exec_handle_sugid(struct image_params *imgp) | |
1398 | { | |
1399 | kauth_cred_t cred = vfs_context_ucred(imgp->ip_vfs_context); | |
1400 | struct proc *p = vfs_context_proc(imgp->ip_vfs_context); | |
1401 | int i; | |
1402 | int error = 0; | |
1403 | static struct vnode *dev_null = NULLVP; | |
1c79356b | 1404 | |
1c79356b | 1405 | p->p_flag &= ~P_SUGID; |
91447636 A |
1406 | |
1407 | if (((imgp->ip_origvattr->va_mode & VSUID) != 0 && | |
1408 | kauth_cred_getuid(cred) != imgp->ip_origvattr->va_uid) || | |
1409 | ((imgp->ip_origvattr->va_mode & VSGID) != 0 && | |
1410 | cred->cr_gid != imgp->ip_origvattr->va_gid)) { | |
1c79356b A |
1411 | #if KTRACE |
1412 | /* | |
1413 | * If process is being ktraced, turn off - unless | |
1414 | * root set it. | |
1415 | */ | |
1416 | if (p->p_tracep && !(p->p_traceflag & KTRFAC_ROOT)) { | |
fa4905b1 | 1417 | struct vnode *tvp = p->p_tracep; |
1c79356b A |
1418 | p->p_tracep = NULL; |
1419 | p->p_traceflag = 0; | |
91447636 | 1420 | vnode_rele(tvp); |
1c79356b A |
1421 | } |
1422 | #endif | |
91447636 A |
1423 | /* |
1424 | * Replace the credential with a copy of itself if euid or egid change. | |
1425 | */ | |
1426 | if (imgp->ip_origvattr->va_mode & VSUID) { | |
1427 | p->p_ucred = kauth_cred_seteuid(p->p_ucred, imgp->ip_origvattr->va_uid); | |
1428 | } | |
1429 | if (imgp->ip_origvattr->va_mode & VSGID) { | |
1430 | p->p_ucred = kauth_cred_setegid(p->p_ucred, imgp->ip_origvattr->va_gid); | |
1431 | } | |
1c79356b | 1432 | |
55e303ae A |
1433 | /* |
1434 | * Have mach reset the task port. We don't want | |
1435 | * anyone who had the task port before a setuid | |
1436 | * exec to be able to access/control the task | |
1437 | * after. | |
1438 | */ | |
91447636 A |
1439 | if (current_task() == p->task) |
1440 | ipc_task_reset(p->task); | |
55e303ae | 1441 | |
1c79356b A |
1442 | p->p_flag |= P_SUGID; |
1443 | ||
91447636 A |
1444 | /* Cache the vnode for /dev/null the first time around */ |
1445 | if (dev_null == NULLVP) { | |
1446 | struct nameidata nd1; | |
1447 | ||
1448 | NDINIT(&nd1, LOOKUP, FOLLOW, UIO_SYSSPACE32, | |
1449 | CAST_USER_ADDR_T("/dev/null"), | |
1450 | imgp->ip_vfs_context); | |
1451 | ||
1452 | if ((error = vn_open(&nd1, FREAD, 0)) == 0) { | |
1453 | dev_null = nd1.ni_vp; | |
1454 | /* | |
1455 | * vn_open returns with both a use_count | |
1456 | * and an io_count on the found vnode | |
1457 | * drop the io_count, but keep the use_count | |
1458 | */ | |
1459 | vnode_put(nd1.ni_vp); | |
1460 | } | |
1461 | } | |
1462 | ||
1c79356b A |
1463 | /* Radar 2261856; setuid security hole fix */ |
1464 | /* Patch from OpenBSD: A. Ramesh */ | |
1465 | /* | |
1466 | * XXX For setuid processes, attempt to ensure that | |
1467 | * stdin, stdout, and stderr are already allocated. | |
1468 | * We do not want userland to accidentally allocate | |
1469 | * descriptors in this range which has implied meaning | |
1470 | * to libc. | |
1471 | */ | |
91447636 A |
1472 | if (dev_null != NULLVP) { |
1473 | for (i = 0; i < 3; i++) { | |
1474 | struct fileproc *fp; | |
1475 | int indx; | |
1476 | ||
1477 | if (p->p_fd->fd_ofiles[i] != NULL) | |
1478 | continue; | |
1c79356b | 1479 | |
1c79356b A |
1480 | if ((error = falloc(p, &fp, &indx)) != 0) |
1481 | continue; | |
91447636 A |
1482 | |
1483 | if ((error = vnode_ref_ext(dev_null, FREAD)) != 0) { | |
1484 | fp_free(p, indx, fp); | |
1c79356b A |
1485 | break; |
1486 | } | |
1c79356b | 1487 | |
91447636 A |
1488 | fp->f_fglob->fg_flag = FREAD; |
1489 | fp->f_fglob->fg_type = DTYPE_VNODE; | |
1490 | fp->f_fglob->fg_ops = &vnops; | |
1491 | fp->f_fglob->fg_data = (caddr_t)dev_null; | |
1492 | ||
1493 | proc_fdlock(p); | |
1494 | *fdflags(p, indx) &= ~UF_RESERVED; | |
1495 | fp_drop(p, indx, fp, 1); | |
1496 | proc_fdunlock(p); | |
1c79356b | 1497 | } |
91447636 A |
1498 | /* |
1499 | * for now we need to drop the reference immediately | |
1500 | * since we don't have any mechanism in place to | |
1501 | * release it before starting to unmount "/dev" | |
1502 | * during a reboot/shutdown | |
1503 | */ | |
1504 | vnode_rele(dev_null); | |
1505 | dev_null = NULLVP; | |
1c79356b | 1506 | } |
1c79356b A |
1507 | } |
1508 | ||
1509 | /* | |
91447636 A |
1510 | * Implement the semantic where the effective user and group become |
1511 | * the saved user and group in exec'ed programs. | |
1c79356b | 1512 | */ |
91447636 A |
1513 | p->p_ucred = kauth_cred_setsvuidgid(p->p_ucred, kauth_cred_getuid(p->p_ucred), p->p_ucred->cr_gid); |
1514 | ||
1515 | /* XXX Obsolete; security token should not be separate from cred */ | |
1516 | set_security_token(p); | |
0b4e3aa0 | 1517 | |
1c79356b A |
1518 | return(error); |
1519 | } | |
1520 | ||
91447636 A |
1521 | static kern_return_t |
1522 | create_unix_stack(vm_map_t map, user_addr_t user_stack, int customstack, | |
1523 | struct proc *p) | |
1c79356b | 1524 | { |
91447636 A |
1525 | mach_vm_size_t size; |
1526 | mach_vm_offset_t addr; | |
1c79356b | 1527 | |
91447636 | 1528 | p->user_stack = user_stack; |
0b4e3aa0 | 1529 | if (!customstack) { |
91447636 A |
1530 | size = mach_vm_round_page(unix_stack_size(p)); |
1531 | addr = mach_vm_trunc_page(user_stack - size); | |
1532 | return (mach_vm_allocate(map, &addr, size, | |
1533 | VM_MAKE_TAG(VM_MEMORY_STACK) | | |
1534 | VM_FLAGS_FIXED)); | |
0b4e3aa0 A |
1535 | } else |
1536 | return(KERN_SUCCESS); | |
1c79356b A |
1537 | } |
1538 | ||
1539 | #include <sys/reboot.h> | |
1540 | ||
91447636 A |
1541 | static char init_program_name[128] = "/sbin/launchd"; |
1542 | static const char * other_init = "/sbin/mach_init"; | |
1c79356b A |
1543 | |
1544 | char init_args[128] = ""; | |
1545 | ||
1546 | struct execve_args init_exec_args; | |
1547 | int init_attempts = 0; | |
1548 | ||
1549 | ||
1550 | void | |
91447636 | 1551 | load_init_program(struct proc *p) |
1c79356b A |
1552 | { |
1553 | vm_offset_t init_addr; | |
1c79356b | 1554 | char *argv[3]; |
91447636 A |
1555 | int error; |
1556 | register_t retval[2]; | |
1c79356b | 1557 | |
1c79356b A |
1558 | error = 0; |
1559 | ||
1560 | /* init_args are copied in string form directly from bootstrap */ | |
1561 | ||
1562 | do { | |
1563 | if (boothowto & RB_INITNAME) { | |
1564 | printf("init program? "); | |
1565 | #if FIXME /* [ */ | |
1566 | gets(init_program_name, init_program_name); | |
1567 | #endif /* FIXME ] */ | |
1568 | } | |
1569 | ||
1570 | if (error && ((boothowto & RB_INITNAME) == 0) && | |
1571 | (init_attempts == 1)) { | |
1c79356b A |
1572 | printf("Load of %s, errno %d, trying %s\n", |
1573 | init_program_name, error, other_init); | |
1574 | error = 0; | |
1575 | bcopy(other_init, init_program_name, | |
1576 | sizeof(other_init)); | |
1577 | } | |
1578 | ||
1579 | init_attempts++; | |
1580 | ||
1581 | if (error) { | |
1582 | printf("Load of %s failed, errno %d\n", | |
1583 | init_program_name, error); | |
1584 | error = 0; | |
1585 | boothowto |= RB_INITNAME; | |
1586 | continue; | |
1587 | } | |
1588 | ||
1589 | /* | |
1590 | * Copy out program name. | |
1591 | */ | |
1592 | ||
1593 | init_addr = VM_MIN_ADDRESS; | |
1594 | (void) vm_allocate(current_map(), &init_addr, | |
91447636 | 1595 | PAGE_SIZE, VM_FLAGS_ANYWHERE); |
1c79356b A |
1596 | if (init_addr == 0) |
1597 | init_addr++; | |
91447636 | 1598 | |
1c79356b | 1599 | (void) copyout((caddr_t) init_program_name, |
91447636 | 1600 | CAST_USER_ADDR_T(init_addr), |
1c79356b A |
1601 | (unsigned) sizeof(init_program_name)+1); |
1602 | ||
1603 | argv[0] = (char *) init_addr; | |
1604 | init_addr += sizeof(init_program_name); | |
1605 | init_addr = (vm_offset_t)ROUND_PTR(char, init_addr); | |
1606 | ||
1607 | /* | |
1608 | * Put out first (and only) argument, similarly. | |
1609 | * Assumes everything fits in a page as allocated | |
1610 | * above. | |
1611 | */ | |
1612 | ||
1613 | (void) copyout((caddr_t) init_args, | |
91447636 | 1614 | CAST_USER_ADDR_T(init_addr), |
1c79356b A |
1615 | (unsigned) sizeof(init_args)); |
1616 | ||
1617 | argv[1] = (char *) init_addr; | |
1618 | init_addr += sizeof(init_args); | |
1619 | init_addr = (vm_offset_t)ROUND_PTR(char, init_addr); | |
1620 | ||
1621 | /* | |
1622 | * Null-end the argument list | |
1623 | */ | |
1624 | ||
1625 | argv[2] = (char *) 0; | |
1626 | ||
1627 | /* | |
1628 | * Copy out the argument list. | |
1629 | */ | |
1630 | ||
1631 | (void) copyout((caddr_t) argv, | |
91447636 | 1632 | CAST_USER_ADDR_T(init_addr), |
1c79356b A |
1633 | (unsigned) sizeof(argv)); |
1634 | ||
1635 | /* | |
1636 | * Set up argument block for fake call to execve. | |
1637 | */ | |
1638 | ||
91447636 A |
1639 | init_exec_args.fname = CAST_USER_ADDR_T(argv[0]); |
1640 | init_exec_args.argp = CAST_USER_ADDR_T((char **)init_addr); | |
1641 | init_exec_args.envp = CAST_USER_ADDR_T(0); | |
1c79356b A |
1642 | |
1643 | /* So that mach_init task | |
1644 | * is set with uid,gid 0 token | |
1645 | */ | |
1646 | set_security_token(p); | |
1647 | ||
1648 | error = execve(p,&init_exec_args,retval); | |
1649 | } while (error); | |
1c79356b A |
1650 | } |
1651 | ||
1652 | /* | |
1653 | * Convert a load_return_t to an errno. | |
1654 | */ | |
1655 | static int | |
1656 | load_return_to_errno(load_return_t lrtn) | |
1657 | { | |
1658 | switch (lrtn) { | |
1659 | case LOAD_SUCCESS: | |
55e303ae | 1660 | return 0; |
1c79356b A |
1661 | case LOAD_BADARCH: |
1662 | return EBADARCH; | |
1663 | case LOAD_BADMACHO: | |
1664 | return EBADMACHO; | |
1665 | case LOAD_SHLIB: | |
1666 | return ESHLIBVERS; | |
1667 | case LOAD_NOSPACE: | |
55e303ae | 1668 | case LOAD_RESOURCE: |
1c79356b A |
1669 | return ENOMEM; |
1670 | case LOAD_PROTECT: | |
1671 | return EACCES; | |
55e303ae A |
1672 | case LOAD_ENOENT: |
1673 | return ENOENT; | |
1674 | case LOAD_IOERROR: | |
1675 | return EIO; | |
1c79356b A |
1676 | case LOAD_FAILURE: |
1677 | default: | |
1678 | return EBADEXEC; | |
1679 | } | |
1680 | } | |
1681 | ||
765c9de3 A |
1682 | #include <mach/mach_types.h> |
1683 | #include <mach/vm_prot.h> | |
1684 | #include <mach/semaphore.h> | |
1685 | #include <mach/sync_policy.h> | |
1686 | #include <kern/clock.h> | |
1687 | #include <mach/kern_return.h> | |
1688 | ||
1689 | extern semaphore_t execve_semaphore; | |
1690 | ||
91447636 A |
1691 | /* |
1692 | * The block of memory used by the execve arguments. At the same time, | |
1693 | * we allocate a page so that we can read in the first page of the image. | |
1694 | */ | |
765c9de3 | 1695 | static int |
91447636 | 1696 | execargs_alloc(struct image_params *imgp) |
765c9de3 A |
1697 | { |
1698 | kern_return_t kret; | |
1699 | ||
1700 | kret = semaphore_wait(execve_semaphore); | |
1701 | if (kret != KERN_SUCCESS) | |
1702 | switch (kret) { | |
1703 | default: | |
1704 | return (EINVAL); | |
1705 | case KERN_INVALID_ADDRESS: | |
1706 | case KERN_PROTECTION_FAILURE: | |
1707 | return (EACCES); | |
1708 | case KERN_ABORTED: | |
1709 | case KERN_OPERATION_TIMED_OUT: | |
1710 | return (EINTR); | |
1711 | } | |
1712 | ||
91447636 A |
1713 | kret = kmem_alloc_pageable(bsd_pageable_map, (vm_offset_t *)&imgp->ip_strings, NCARGS + PAGE_SIZE); |
1714 | imgp->ip_vdata = imgp->ip_strings + NCARGS; | |
55e303ae A |
1715 | if (kret != KERN_SUCCESS) { |
1716 | semaphore_signal(execve_semaphore); | |
765c9de3 | 1717 | return (ENOMEM); |
55e303ae | 1718 | } |
765c9de3 A |
1719 | return (0); |
1720 | } | |
1721 | ||
1722 | static int | |
91447636 | 1723 | execargs_free(struct image_params *imgp) |
765c9de3 A |
1724 | { |
1725 | kern_return_t kret; | |
1726 | ||
91447636 A |
1727 | kmem_free(bsd_pageable_map, (vm_offset_t)imgp->ip_strings, NCARGS + PAGE_SIZE); |
1728 | imgp->ip_strings = NULL; | |
765c9de3 A |
1729 | |
1730 | kret = semaphore_signal(execve_semaphore); | |
1731 | switch (kret) { | |
1732 | case KERN_INVALID_ADDRESS: | |
1733 | case KERN_PROTECTION_FAILURE: | |
1734 | return (EINVAL); | |
1735 | case KERN_ABORTED: | |
1736 | case KERN_OPERATION_TIMED_OUT: | |
1737 | return (EINTR); | |
1738 | case KERN_SUCCESS: | |
1739 | return(0); | |
1740 | default: | |
1741 | return (EINVAL); | |
1742 | } | |
1743 | } |