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