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