]> git.saurik.com Git - apple/xnu.git/blame - bsd/kern/mach_loader.c
xnu-792.10.96.tar.gz
[apple/xnu.git] / bsd / kern / mach_loader.c
CommitLineData
1c79356b 1/*
91447636 2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
1c79356b
A
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
37839358
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 *
37839358
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,
37839358
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/*
23 * Copyright (C) 1988, 1989, NeXT, Inc.
24 *
25 * File: kern/mach_loader.c
26 * Author: Avadis Tevanian, Jr.
27 *
28 * Mach object file loader (kernel version, for now).
29 *
30 * 21-Jul-88 Avadis Tevanian, Jr. (avie) at NeXT
31 * Started.
32 */
91447636 33
1c79356b 34#include <sys/param.h>
91447636 35#include <sys/vnode_internal.h>
1c79356b
A
36#include <sys/uio.h>
37#include <sys/namei.h>
91447636
A
38#include <sys/proc_internal.h>
39#include <sys/kauth.h>
1c79356b
A
40#include <sys/stat.h>
41#include <sys/malloc.h>
91447636 42#include <sys/mount_internal.h>
1c79356b 43#include <sys/fcntl.h>
91447636
A
44#include <sys/ubc_internal.h>
45#include <sys/imgact.h>
1c79356b 46
1c79356b 47#include <mach/mach_types.h>
91447636
A
48#include <mach/vm_map.h> /* vm_allocate() */
49#include <mach/mach_vm.h> /* mach_vm_allocate() */
50#include <mach/vm_statistics.h>
51#include <mach/shared_memory_server.h>
52#include <mach/task.h>
53#include <mach/thread_act.h>
54
55#include <machine/vmparam.h>
1c79356b 56
91447636
A
57#include <kern/kern_types.h>
58#include <kern/cpu_number.h>
1c79356b 59#include <kern/mach_loader.h>
91447636 60#include <kern/kalloc.h>
55e303ae 61#include <kern/task.h>
91447636 62#include <kern/thread.h>
1c79356b
A
63
64#include <mach-o/fat.h>
65#include <mach-o/loader.h>
66
91447636 67#include <vm/pmap.h>
1c79356b
A
68#include <vm/vm_map.h>
69#include <vm/vm_kern.h>
70#include <vm/vm_pager.h>
71#include <vm/vnode_pager.h>
9bccf70c 72#include <vm/vm_shared_memory_server.h>
91447636 73#include <vm/vm_protos.h>
9bccf70c 74
91447636
A
75/*
76 * XXX vm/pmap.h should not treat these prototypes as MACH_KERNEL_PRIVATE
77 * when KERNEL is defined.
78 */
c0fea474 79extern pmap_t pmap_create(vm_map_size_t size, boolean_t is_64bit);
91447636
A
80extern void pmap_switch(pmap_t);
81extern void pmap_map_sharedpage(task_t task, pmap_t pmap);
82
83/*
84 * XXX kern/thread.h should not treat these prototypes as MACH_KERNEL_PRIVATE
85 * when KERNEL is defined.
86 */
87extern kern_return_t thread_setstatus(thread_t thread, int flavor,
88 thread_state_t tstate,
89 mach_msg_type_number_t count);
90
91extern kern_return_t thread_state_initialize(thread_t thread);
92
93
94/* XXX should have prototypes in a shared header file */
91447636
A
95extern int get_map_nentries(vm_map_t);
96extern kern_return_t thread_userstack(thread_t, int, thread_state_t,
97 unsigned int, mach_vm_offset_t *, int *);
98extern kern_return_t thread_entrypoint(thread_t, int, thread_state_t,
99 unsigned int, mach_vm_offset_t *);
100
101
102/* An empty load_result_t */
103static load_result_t load_result_null = {
104 MACH_VM_MIN_ADDRESS,
105 MACH_VM_MIN_ADDRESS,
106 MACH_VM_MIN_ADDRESS,
107 0,
108 0,
109 0,
110 0
111};
9bccf70c 112
1c79356b
A
113/*
114 * Prototypes of static functions.
115 */
91447636 116static load_return_t
1c79356b
A
117parse_machfile(
118 struct vnode *vp,
91447636
A
119 vm_map_t map,
120 thread_t thr_act,
1c79356b 121 struct mach_header *header,
91447636
A
122 off_t file_offset,
123 off_t macho_size,
124 boolean_t shared_regions,
125 boolean_t clean_regions,
126 int depth,
127 load_result_t *result
128);
129
130static load_return_t
1c79356b
A
131load_segment(
132 struct segment_command *scp,
0b4e3aa0 133 void * pager,
91447636
A
134 off_t pager_offset,
135 off_t macho_size,
136 off_t end_of_file,
0b4e3aa0
A
137 vm_map_t map,
138 load_result_t *result
91447636
A
139);
140
141static load_return_t
142load_segment_64(
143 struct segment_command_64 *scp64,
144 void *pager,
145 off_t pager_offset,
146 off_t macho_size,
147 off_t end_of_file,
148 vm_map_t map,
149 load_result_t *result
150);
151
152static load_return_t
1c79356b
A
153load_unixthread(
154 struct thread_command *tcp,
91447636 155 thread_t thr_act,
0b4e3aa0 156 load_result_t *result
91447636
A
157);
158
159static load_return_t
1c79356b
A
160load_thread(
161 struct thread_command *tcp,
91447636 162 thread_t thr_act,
0b4e3aa0 163 load_result_t *result
91447636
A
164);
165
166static load_return_t
1c79356b 167load_threadstate(
0b4e3aa0 168 thread_t thread,
1c79356b
A
169 unsigned long *ts,
170 unsigned long total_size
91447636
A
171);
172
173static load_return_t
1c79356b 174load_threadstack(
0b4e3aa0 175 thread_t thread,
1c79356b
A
176 unsigned long *ts,
177 unsigned long total_size,
91447636 178 mach_vm_offset_t *user_stack,
0b4e3aa0 179 int *customstack
91447636
A
180);
181
182static load_return_t
1c79356b 183load_threadentry(
0b4e3aa0 184 thread_t thread,
1c79356b
A
185 unsigned long *ts,
186 unsigned long total_size,
91447636
A
187 mach_vm_offset_t *entry_point
188);
189
190static load_return_t
1c79356b
A
191load_dylinker(
192 struct dylinker_command *lcp,
91447636 193 integer_t archbits,
0b4e3aa0 194 vm_map_t map,
91447636 195 thread_t thr_act,
0b4e3aa0 196 int depth,
55e303ae 197 load_result_t *result,
c0fea474
A
198 boolean_t clean_regions,
199 boolean_t is_64bit
91447636
A
200);
201
202static load_return_t
1c79356b 203get_macho_vnode(
0b4e3aa0 204 char *path,
91447636 205 integer_t archbits,
1c79356b 206 struct mach_header *mach_header,
91447636
A
207 off_t *file_offset,
208 off_t *macho_size,
1c79356b
A
209 struct vnode **vpp
210);
211
212load_return_t
213load_machfile(
91447636 214 struct image_params *imgp,
1c79356b 215 struct mach_header *header,
91447636 216 thread_t thr_act,
55e303ae 217 vm_map_t new_map,
91447636
A
218 boolean_t clean_regions,
219 load_result_t *result
1c79356b
A
220)
221{
91447636
A
222 struct vnode *vp = imgp->ip_vp;
223 off_t file_offset = imgp->ip_arch_offset;
224 off_t macho_size = imgp->ip_arch_size;
225
226 pmap_t pmap = 0; /* protected by create_map */
1c79356b
A
227 vm_map_t map;
228 vm_map_t old_map;
229 load_result_t myresult;
1c79356b 230 load_return_t lret;
0b4e3aa0
A
231 boolean_t create_map = TRUE;
232
233 if (new_map != VM_MAP_NULL) {
234 create_map = FALSE;
235 }
1c79356b 236
0b4e3aa0
A
237 if (create_map) {
238 old_map = current_map();
c0fea474 239#ifdef NO_NESTED_PMAP
0b4e3aa0
A
240 pmap = get_task_pmap(current_task());
241 pmap_reference(pmap);
c0fea474
A
242#else /* NO_NESTED_PMAP */
243 pmap = pmap_create((vm_map_size_t) 0, (imgp->ip_flags & IMGPF_IS_64BIT));
244#endif /* NO_NESTED_PMAP */
0b4e3aa0 245 map = vm_map_create(pmap,
c0fea474
A
246 0,
247 vm_compute_max_offset((imgp->ip_flags & IMGPF_IS_64BIT)),
248 TRUE);
0b4e3aa0
A
249 } else
250 map = new_map;
c0fea474
A
251
252 if ( (header->flags & MH_ALLOW_STACK_EXECUTION) )
253 vm_map_disable_NX(map);
254
1c79356b
A
255 if (!result)
256 result = &myresult;
257
91447636 258 *result = load_result_null;
1c79356b 259
0b4e3aa0 260 lret = parse_machfile(vp, map, thr_act, header, file_offset, macho_size,
91447636
A
261 ((imgp->ip_flags & IMGPF_IS_64BIT) == 0), /* shared regions? */
262 clean_regions, 0, result);
1c79356b
A
263
264 if (lret != LOAD_SUCCESS) {
55e303ae 265 if (create_map) {
0b4e3aa0 266 vm_map_deallocate(map); /* will lose pmap reference too */
55e303ae 267 }
1c79356b
A
268 return(lret);
269 }
55e303ae 270
c0fea474
A
271 /*
272 * For 64-bit users, check for presence of a 4GB page zero
273 * which will enable the kernel to share the user's address space
274 * and hence avoid TLB flushes on kernel entry/exit
275 */
276 if ((imgp->ip_flags & IMGPF_IS_64BIT) &&
277 vm_map_has_4GB_pagezero(map))
278 vm_map_set_4GB_pagezero(map);
279
1c79356b
A
280 /*
281 * Commit to new map. First make sure that the current
282 * users of the task get done with it, and that we clean
283 * up the old contents of IPC and memory. The task is
284 * guaranteed to be single threaded upon return (us).
285 *
55e303ae
A
286 * Swap the new map for the old, which consumes our new map
287 * reference but each leaves us responsible for the old_map reference.
1c79356b
A
288 * That lets us get off the pmap associated with it, and
289 * then we can release it.
290 */
c0fea474 291
0b4e3aa0
A
292 if (create_map) {
293 task_halt(current_task());
1c79356b 294
0b4e3aa0 295 old_map = swap_task_map(current_task(), map);
c0fea474
A
296 vm_map_clear_4GB_pagezero(old_map);
297#ifndef NO_NESTED_PMAP
0b4e3aa0 298 pmap_switch(pmap); /* Make sure we are using the new pmap */
c0fea474 299#endif /* !NO_NESTED_PMAP */
0b4e3aa0
A
300 vm_map_deallocate(old_map);
301 }
1c79356b
A
302 return(LOAD_SUCCESS);
303}
304
305int dylink_test = 1;
1c79356b 306
91447636
A
307/*
308 * The file size of a mach-o file is limited to 32 bits; this is because
309 * this is the limit on the kalloc() of enough bytes for a mach_header and
310 * the contents of its sizeofcmds, which is currently constrained to 32
311 * bits in the file format itself. We read into the kernel buffer the
312 * commands section, and then parse it in order to parse the mach-o file
313 * format load_command segment(s). We are only interested in a subset of
314 * the total set of possible commands.
315 */
1c79356b
A
316static
317load_return_t
318parse_machfile(
91447636 319 struct vnode *vp,
1c79356b 320 vm_map_t map,
91447636 321 thread_t thr_act,
1c79356b 322 struct mach_header *header,
91447636
A
323 off_t file_offset,
324 off_t macho_size,
325 boolean_t shared_regions,
326 boolean_t clean_regions,
1c79356b 327 int depth,
91447636 328 load_result_t *result
1c79356b
A
329)
330{
a3d08fcd 331 uint32_t ncmds;
91447636 332 struct load_command *lcp;
1c79356b 333 struct dylinker_command *dlp = 0;
91447636 334 integer_t dlarchbits = 0;
1c79356b 335 void * pager;
55e303ae 336 load_return_t ret = LOAD_SUCCESS;
91447636
A
337 caddr_t addr;
338 void * kl_addr;
1c79356b 339 vm_size_t size,kl_size;
a3d08fcd
A
340 size_t offset;
341 size_t oldoffset; /* for overflow check */
1c79356b
A
342 int pass;
343 struct proc *p = current_proc(); /* XXXX */
344 int error;
345 int resid=0;
0b4e3aa0 346 task_t task;
91447636
A
347 size_t mach_header_sz = sizeof(struct mach_header);
348 boolean_t abi64;
349
350 if (header->magic == MH_MAGIC_64 ||
351 header->magic == MH_CIGAM_64) {
352 mach_header_sz = sizeof(struct mach_header_64);
353 }
1c79356b
A
354
355 /*
356 * Break infinite recursion
357 */
358 if (depth > 6)
359 return(LOAD_FAILURE);
0b4e3aa0
A
360
361 task = (task_t)get_threadtask(thr_act);
362
1c79356b
A
363 depth++;
364
365 /*
366 * Check to see if right machine type.
367 */
91447636
A
368 if (((cpu_type_t)(header->cputype & ~CPU_ARCH_MASK) != cpu_type()) ||
369 !grade_binary(header->cputype, header->cpusubtype))
1c79356b
A
370 return(LOAD_BADARCH);
371
91447636
A
372 abi64 = ((header->cputype & CPU_ARCH_ABI64) == CPU_ARCH_ABI64);
373
1c79356b
A
374 switch (header->filetype) {
375
376 case MH_OBJECT:
377 case MH_EXECUTE:
378 case MH_PRELOAD:
379 if (depth != 1)
380 return (LOAD_FAILURE);
381 break;
382
383 case MH_FVMLIB:
384 case MH_DYLIB:
385 if (depth == 1)
386 return (LOAD_FAILURE);
387 break;
388
389 case MH_DYLINKER:
390 if (depth != 2)
391 return (LOAD_FAILURE);
392 break;
393
394 default:
395 return (LOAD_FAILURE);
396 }
397
398 /*
399 * Get the pager for the file.
400 */
401 UBCINFOCHECK("parse_machfile", vp);
402 pager = (void *) ubc_getpager(vp);
403
404 /*
405 * Map portion that must be accessible directly into
406 * kernel's map.
407 */
91447636 408 if ((mach_header_sz + header->sizeofcmds) > macho_size)
1c79356b
A
409 return(LOAD_BADMACHO);
410
411 /*
412 * Round size of Mach-O commands up to page boundry.
413 */
91447636 414 size = round_page(mach_header_sz + header->sizeofcmds);
1c79356b
A
415 if (size <= 0)
416 return(LOAD_BADMACHO);
417
418 /*
419 * Map the load commands into kernel memory.
420 */
421 addr = 0;
1c79356b
A
422 kl_size = size;
423 kl_addr = kalloc(size);
91447636 424 addr = (caddr_t)kl_addr;
0b4e3aa0 425 if (addr == NULL)
1c79356b 426 return(LOAD_NOSPACE);
0b4e3aa0 427
91447636
A
428 error = vn_rdwr(UIO_READ, vp, addr, size, file_offset,
429 UIO_SYSSPACE32, 0, kauth_cred_get(), &resid, p);
430 if (error) {
0b4e3aa0
A
431 if (kl_addr )
432 kfree(kl_addr, kl_size);
55e303ae 433 return(LOAD_IOERROR);
1c79356b 434 }
91447636 435 /* (void)ubc_map(vp, PROT_EXEC); */ /* NOT HERE */
1c79356b 436
1c79356b
A
437 /*
438 * Scan through the commands, processing each one as necessary.
439 */
440 for (pass = 1; pass <= 2; pass++) {
a3d08fcd
A
441 /*
442 * Loop through each of the load_commands indicated by the
443 * Mach-O header; if an absurd value is provided, we just
444 * run off the end of the reserved section by incrementing
445 * the offset too far, so we are implicitly fail-safe.
446 */
91447636 447 offset = mach_header_sz;
1c79356b
A
448 ncmds = header->ncmds;
449 while (ncmds--) {
450 /*
451 * Get a pointer to the command.
452 */
453 lcp = (struct load_command *)(addr + offset);
a3d08fcd 454 oldoffset = offset;
1c79356b
A
455 offset += lcp->cmdsize;
456
457 /*
a3d08fcd
A
458 * Perform prevalidation of the struct load_command
459 * before we attempt to use its contents. Invalid
460 * values are ones which result in an overflow, or
461 * which can not possibly be valid commands, or which
462 * straddle or exist past the reserved section at the
463 * start of the image.
1c79356b 464 */
a3d08fcd
A
465 if (oldoffset > offset ||
466 lcp->cmdsize < sizeof(struct load_command) ||
91447636
A
467 offset > header->sizeofcmds + mach_header_sz) {
468 ret = LOAD_BADMACHO;
a3d08fcd 469 break;
1c79356b
A
470 }
471
472 /*
a3d08fcd
A
473 * Act on struct load_command's for which kernel
474 * intervention is required.
1c79356b
A
475 */
476 switch(lcp->cmd) {
91447636
A
477 case LC_SEGMENT_64:
478 if (pass != 1)
479 break;
480 ret = load_segment_64(
481 (struct segment_command_64 *)lcp,
482 pager,
483 file_offset,
484 macho_size,
485 ubc_getsize(vp),
486 map,
487 result);
488 break;
1c79356b
A
489 case LC_SEGMENT:
490 if (pass != 1)
491 break;
492 ret = load_segment(
493 (struct segment_command *) lcp,
91447636
A
494 pager,
495 file_offset,
1c79356b 496 macho_size,
91447636 497 ubc_getsize(vp),
1c79356b
A
498 map,
499 result);
500 break;
501 case LC_THREAD:
502 if (pass != 2)
503 break;
91447636
A
504 ret = load_thread((struct thread_command *)lcp,
505 thr_act,
1c79356b
A
506 result);
507 break;
508 case LC_UNIXTHREAD:
509 if (pass != 2)
510 break;
511 ret = load_unixthread(
91447636
A
512 (struct thread_command *) lcp,
513 thr_act,
1c79356b
A
514 result);
515 break;
1c79356b
A
516 case LC_LOAD_DYLINKER:
517 if (pass != 2)
518 break;
91447636 519 if ((depth == 1) && (dlp == 0)) {
1c79356b 520 dlp = (struct dylinker_command *)lcp;
91447636
A
521 dlarchbits = (header->cputype & CPU_ARCH_MASK);
522 } else {
1c79356b 523 ret = LOAD_FAILURE;
91447636 524 }
1c79356b
A
525 break;
526 default:
a3d08fcd
A
527 /* Other commands are ignored by the kernel */
528 ret = LOAD_SUCCESS;
91447636 529 break;
1c79356b
A
530 }
531 if (ret != LOAD_SUCCESS)
532 break;
533 }
534 if (ret != LOAD_SUCCESS)
535 break;
536 }
91447636
A
537 if (ret == LOAD_SUCCESS) {
538
539 if (shared_regions) {
540 vm_offset_t vmaddr;
1c79356b
A
541 shared_region_mapping_t shared_region;
542 struct shared_region_task_mappings map_info;
543 shared_region_mapping_t next;
544
545RedoLookup:
0b4e3aa0 546 vm_get_shared_region(task, &shared_region);
1c79356b
A
547 map_info.self = (vm_offset_t)shared_region;
548 shared_region_mapping_info(shared_region,
549 &(map_info.text_region),
550 &(map_info.text_size),
551 &(map_info.data_region),
552 &(map_info.data_size),
553 &(map_info.region_mappings),
554 &(map_info.client_base),
555 &(map_info.alternate_base),
556 &(map_info.alternate_next),
55e303ae
A
557 &(map_info.fs_base),
558 &(map_info.system),
1c79356b
A
559 &(map_info.flags), &next);
560
55e303ae
A
561 if((map_info.flags & SHARED_REGION_FULL) ||
562 (map_info.flags & SHARED_REGION_STALE)) {
563 shared_region_mapping_t system_region;
564 system_region = lookup_default_shared_region(
565 map_info.fs_base, map_info.system);
566 if((map_info.self != (vm_offset_t)system_region) &&
567 (map_info.flags & SHARED_REGION_SYSTEM)) {
568 if(system_region == NULL) {
569 shared_file_boot_time_init(
570 map_info.fs_base, map_info.system);
571 } else {
572 vm_set_shared_region(task, system_region);
573 }
574 shared_region_mapping_dealloc(
1c79356b 575 (shared_region_mapping_t)map_info.self);
55e303ae
A
576 goto RedoLookup;
577 } else if (map_info.flags & SHARED_REGION_SYSTEM) {
578 shared_region_mapping_dealloc(system_region);
579 shared_file_boot_time_init(
580 map_info.fs_base, map_info.system);
581 shared_region_mapping_dealloc(
582 (shared_region_mapping_t)map_info.self);
583 } else {
584 shared_region_mapping_dealloc(system_region);
585 }
1c79356b
A
586 }
587
1c79356b 588 if (dylink_test) {
9bccf70c 589 p->p_flag |= P_NOSHLIB; /* no shlibs in use */
91447636 590 vmaddr = map_info.client_base;
55e303ae 591 if(clean_regions) {
91447636
A
592 vm_map(map, &vmaddr, map_info.text_size,
593 0, SHARED_LIB_ALIAS|VM_FLAGS_FIXED,
55e303ae
A
594 map_info.text_region, 0, FALSE,
595 VM_PROT_READ, VM_PROT_READ, VM_INHERIT_SHARE);
596 } else {
91447636 597 vm_map(map, &vmaddr, map_info.text_size, 0,
1c79356b 598 (VM_MEMORY_SHARED_PMAP << 24)
91447636 599 | SHARED_LIB_ALIAS | VM_FLAGS_FIXED,
1c79356b
A
600 map_info.text_region, 0, FALSE,
601 VM_PROT_READ, VM_PROT_READ, VM_INHERIT_SHARE);
55e303ae 602 }
91447636
A
603 vmaddr = map_info.client_base + map_info.text_size;
604 vm_map(map, &vmaddr, map_info.data_size,
605 0, SHARED_LIB_ALIAS | VM_FLAGS_FIXED,
1c79356b
A
606 map_info.data_region, 0, TRUE,
607 VM_PROT_READ, VM_PROT_READ, VM_INHERIT_SHARE);
55e303ae
A
608
609 while (next) {
610 /* this should be fleshed out for the general case */
611 /* but this is not necessary for now. Indeed we */
612 /* are handling the com page inside of the */
613 /* shared_region mapping create calls for now for */
614 /* simplicities sake. If more general support is */
615 /* needed the code to manipulate the shared range */
616 /* chain can be pulled out and moved to the callers*/
617 shared_region_mapping_info(next,
618 &(map_info.text_region),
619 &(map_info.text_size),
620 &(map_info.data_region),
621 &(map_info.data_size),
622 &(map_info.region_mappings),
623 &(map_info.client_base),
624 &(map_info.alternate_base),
625 &(map_info.alternate_next),
626 &(map_info.fs_base),
627 &(map_info.system),
628 &(map_info.flags), &next);
629
91447636
A
630 vmaddr = map_info.client_base;
631 vm_map(map, &vmaddr, map_info.text_size,
632 0, SHARED_LIB_ALIAS | VM_FLAGS_FIXED,
55e303ae
A
633 map_info.text_region, 0, FALSE,
634 VM_PROT_READ, VM_PROT_READ, VM_INHERIT_SHARE);
635 }
1c79356b 636 }
91447636
A
637 }
638 if (dlp != 0)
c0fea474 639 ret = load_dylinker(dlp, dlarchbits, map, thr_act, depth, result, clean_regions, abi64);
91447636
A
640
641 if(depth == 1) {
642 if (result->thread_count == 0)
643 ret = LOAD_FAILURE;
91447636
A
644 else if ( abi64 ) {
645 /* Map in 64-bit commpage */
646 /* LP64todo - make this clean */
647 pmap_map_sharedpage(current_task(), get_map_pmap(map));
648 vm_map_commpage64(map);
c0fea474
A
649 } else {
650#ifdef __i386__
651 /*
652 * On Intel, the comm page doesn't get mapped
653 * automatically because it goes beyond the current end
654 * of the VM map in the current 3GB/1GB address space
655 * model.
656 * XXX This will probably become unnecessary when we
657 * switch to the 4GB/4GB address space model.
658 */
659 vm_map_commpage32(map);
660#endif /* __i386__ */
91447636 661 }
91447636 662 }
1c79356b
A
663 }
664
0b4e3aa0
A
665 if (kl_addr )
666 kfree(kl_addr, kl_size);
667
1c79356b 668 if (ret == LOAD_SUCCESS)
91447636 669 (void)ubc_map(vp, PROT_EXEC);
1c79356b
A
670
671 return(ret);
672}
673
c0fea474
A
674#ifndef SG_PROTECTED_VERSION_1
675#define SG_PROTECTED_VERSION_1 0x8
676#endif /* SG_PROTECTED_VERSION_1 */
677
678#ifdef __i386__
679
680#define APPLE_UNPROTECTED_HEADER_SIZE (3 * PAGE_SIZE_64)
681
682static load_return_t
683unprotect_segment_64(
684 uint64_t file_off,
685 uint64_t file_size,
686 vm_map_t map,
687 vm_map_offset_t map_addr,
688 vm_map_size_t map_size)
689{
690 kern_return_t kr;
691
692 /*
693 * The first APPLE_UNPROTECTED_HEADER_SIZE bytes (from offset 0 of
694 * this part of a Universal binary) are not protected...
695 * The rest needs to be "transformed".
696 */
697 if (file_off <= APPLE_UNPROTECTED_HEADER_SIZE &&
698 file_off + file_size <= APPLE_UNPROTECTED_HEADER_SIZE) {
699 /* it's all unprotected, nothing to do... */
700 kr = KERN_SUCCESS;
701 } else {
702 if (file_off <= APPLE_UNPROTECTED_HEADER_SIZE) {
703 /*
704 * We start mapping in the unprotected area.
705 * Skip the unprotected part...
706 */
707 vm_map_offset_t delta;
708
709 delta = APPLE_UNPROTECTED_HEADER_SIZE;
710 delta -= file_off;
711 map_addr += delta;
712 map_size -= delta;
713 }
714 /* ... transform the rest of the mapping. */
715 kr = vm_map_apple_protected(map,
716 map_addr,
717 map_addr + map_size);
718 }
719
720 if (kr != KERN_SUCCESS) {
721 return LOAD_FAILURE;
722 }
723 return LOAD_SUCCESS;
724}
725#else /* __i386__ */
726#define unprotect_segment_64(file_off, file_size, map, map_addr, map_size) \
727 LOAD_SUCCESS
728#endif /* __i386__ */
729
1c79356b
A
730static
731load_return_t
732load_segment(
733 struct segment_command *scp,
734 void * pager,
91447636
A
735 off_t pager_offset,
736 off_t macho_size,
737 __unused off_t end_of_file,
1c79356b
A
738 vm_map_t map,
739 load_result_t *result
740)
741{
742 kern_return_t ret;
743 vm_offset_t map_addr, map_offset;
744 vm_size_t map_size, seg_size, delta_size;
1c79356b
A
745 vm_prot_t initprot;
746 vm_prot_t maxprot;
1c79356b
A
747
748 /*
749 * Make sure what we get from the file is really ours (as specified
750 * by macho_size).
751 */
752 if (scp->fileoff + scp->filesize > macho_size)
753 return (LOAD_BADMACHO);
754
91447636 755 seg_size = round_page(scp->vmsize);
1c79356b
A
756 if (seg_size == 0)
757 return(KERN_SUCCESS);
758
759 /*
760 * Round sizes to page size.
761 */
91447636
A
762 map_size = round_page(scp->filesize);
763 map_addr = trunc_page(scp->vmaddr);
1c79356b 764
c0fea474
A
765#if 0 /* XXX (4596982) this interferes with Rosetta */
766 if (map_addr == 0 &&
767 map_size == 0 &&
768 seg_size != 0 &&
769 (scp->initprot & VM_PROT_ALL) == VM_PROT_NONE &&
770 (scp->maxprot & VM_PROT_ALL) == VM_PROT_NONE) {
771 /*
772 * This is a "page zero" segment: it starts at address 0,
773 * is not mapped from the binary file and is not accessible.
774 * User-space should never be able to access that memory, so
775 * make it completely off limits by raising the VM map's
776 * minimum offset.
777 */
778 ret = vm_map_raise_min_offset(map, (vm_map_offset_t) seg_size);
779 if (ret != KERN_SUCCESS) {
780 return LOAD_FAILURE;
781 }
782 return LOAD_SUCCESS;
783 }
784#endif
785
1c79356b
A
786 map_offset = pager_offset + scp->fileoff;
787
788 if (map_size > 0) {
789 initprot = (scp->initprot) & VM_PROT_ALL;
790 maxprot = (scp->maxprot) & VM_PROT_ALL;
791 /*
792 * Map a copy of the file into the address space.
793 */
794 ret = vm_map(map,
91447636
A
795 &map_addr, map_size, (vm_offset_t)0,
796 VM_FLAGS_FIXED, pager, map_offset, TRUE,
1c79356b
A
797 initprot, maxprot,
798 VM_INHERIT_DEFAULT);
799 if (ret != KERN_SUCCESS)
800 return(LOAD_NOSPACE);
801
1c79356b
A
802 /*
803 * If the file didn't end on a page boundary,
804 * we need to zero the leftover.
805 */
806 delta_size = map_size - scp->filesize;
807#if FIXME
808 if (delta_size > 0) {
809 vm_offset_t tmp;
810
91447636 811 ret = vm_allocate(kernel_map, &tmp, delta_size, VM_FLAGS_ANYWHERE);
1c79356b
A
812 if (ret != KERN_SUCCESS)
813 return(LOAD_RESOURCE);
814
815 if (copyout(tmp, map_addr + scp->filesize,
816 delta_size)) {
817 (void) vm_deallocate(
818 kernel_map, tmp, delta_size);
819 return(LOAD_FAILURE);
820 }
821
822 (void) vm_deallocate(kernel_map, tmp, delta_size);
823 }
824#endif /* FIXME */
825 }
826
827 /*
828 * If the virtual size of the segment is greater
829 * than the size from the file, we need to allocate
830 * zero fill memory for the rest.
831 */
832 delta_size = seg_size - map_size;
833 if (delta_size > 0) {
834 vm_offset_t tmp = map_addr + map_size;
835
c0fea474
A
836 ret = vm_map(map, &tmp, delta_size, 0, VM_FLAGS_FIXED,
837 NULL, 0, FALSE,
838 scp->initprot, scp->maxprot,
839 VM_INHERIT_DEFAULT);
1c79356b
A
840 if (ret != KERN_SUCCESS)
841 return(LOAD_NOSPACE);
842 }
843
1c79356b
A
844 if ( (scp->fileoff == 0) && (scp->filesize != 0) )
845 result->mach_header = map_addr;
c0fea474
A
846
847 if (scp->flags & SG_PROTECTED_VERSION_1) {
848 ret = unprotect_segment_64((uint64_t) scp->fileoff,
849 (uint64_t) scp->filesize,
850 map,
851 (vm_map_offset_t) map_addr,
852 (vm_map_size_t) map_size);
853 } else {
854 ret = LOAD_SUCCESS;
855 }
856
857 return ret;
1c79356b
A
858}
859
860static
861load_return_t
91447636
A
862load_segment_64(
863 struct segment_command_64 *scp64,
864 void * pager,
865 off_t pager_offset,
866 off_t macho_size,
867 __unused off_t end_of_file,
868 vm_map_t map,
1c79356b
A
869 load_result_t *result
870)
871{
91447636
A
872 kern_return_t ret;
873 mach_vm_offset_t map_addr, map_offset;
874 mach_vm_size_t map_size, seg_size, delta_size;
875 vm_prot_t initprot;
876 vm_prot_t maxprot;
1c79356b 877
91447636
A
878 /*
879 * Make sure what we get from the file is really ours (as specified
880 * by macho_size).
881 */
882 if (scp64->fileoff + scp64->filesize > (uint64_t)macho_size)
883 return (LOAD_BADMACHO);
884
885 seg_size = round_page_64(scp64->vmsize);
886 if (seg_size == 0)
887 return(KERN_SUCCESS);
888
889 /*
890 * Round sizes to page size.
891 */
892 map_size = round_page_64(scp64->filesize); /* limited to 32 bits */
893 map_addr = round_page_64(scp64->vmaddr);
894
c0fea474
A
895 if (map_addr == 0 &&
896 map_size == 0 &&
897 seg_size != 0 &&
898 (scp64->initprot & VM_PROT_ALL) == VM_PROT_NONE &&
899 (scp64->maxprot & VM_PROT_ALL) == VM_PROT_NONE) {
900 /*
901 * This is a "page zero" segment: it starts at address 0,
902 * is not mapped from the binary file and is not accessible.
903 * User-space should never be able to access that memory, so
904 * make it completely off limits by raising the VM map's
905 * minimum offset.
906 */
907 ret = vm_map_raise_min_offset(map, seg_size);
908 if (ret != KERN_SUCCESS) {
909 return LOAD_FAILURE;
910 }
911 return LOAD_SUCCESS;
912 }
913
91447636
A
914 map_offset = pager_offset + scp64->fileoff; /* limited to 32 bits */
915
916 if (map_size > 0) {
917 initprot = (scp64->initprot) & VM_PROT_ALL;
918 maxprot = (scp64->maxprot) & VM_PROT_ALL;
919 /*
920 * Map a copy of the file into the address space.
921 */
922 ret = mach_vm_map(map,
923 &map_addr, map_size, (mach_vm_offset_t)0,
924 VM_FLAGS_FIXED, pager, map_offset, TRUE,
925 initprot, maxprot,
926 VM_INHERIT_DEFAULT);
927 if (ret != KERN_SUCCESS)
928 return(LOAD_NOSPACE);
929
930 /*
931 * If the file didn't end on a page boundary,
932 * we need to zero the leftover.
933 */
934 delta_size = map_size - scp64->filesize;
935#if FIXME
936 if (delta_size > 0) {
937 mach_vm_offset_t tmp;
938
939 ret = vm_allocate(kernel_map, &tmp, delta_size, VM_FLAGS_ANYWHERE);
940 if (ret != KERN_SUCCESS)
941 return(LOAD_RESOURCE);
942
943 if (copyout(tmp, map_addr + scp64->filesize,
944 delta_size)) {
945 (void) vm_deallocate(
946 kernel_map, tmp, delta_size);
1c79356b 947 return (LOAD_FAILURE);
91447636 948 }
1c79356b 949
91447636
A
950 (void) vm_deallocate(kernel_map, tmp, delta_size);
951 }
952#endif /* FIXME */
953 }
1c79356b 954
91447636
A
955 /*
956 * If the virtual size of the segment is greater
957 * than the size from the file, we need to allocate
958 * zero fill memory for the rest.
959 */
960 delta_size = seg_size - map_size;
961 if (delta_size > 0) {
962 mach_vm_offset_t tmp = map_addr + map_size;
1c79356b 963
c0fea474
A
964 ret = mach_vm_map(map, &tmp, delta_size, 0, VM_FLAGS_FIXED,
965 NULL, 0, FALSE,
966 scp64->initprot, scp64->maxprot,
967 VM_INHERIT_DEFAULT);
91447636
A
968 if (ret != KERN_SUCCESS)
969 return(LOAD_NOSPACE);
970 }
1c79356b 971
91447636
A
972 if ( (scp64->fileoff == 0) && (scp64->filesize != 0) )
973 result->mach_header = map_addr;
c0fea474
A
974
975 if (scp64->flags & SG_PROTECTED_VERSION_1) {
976 ret = unprotect_segment_64(scp64->fileoff,
977 scp64->filesize,
978 map,
979 map_addr,
980 map_size);
981 } else {
982 ret = LOAD_SUCCESS;
983 }
984
985 return ret;
1c79356b
A
986}
987
988static
989load_return_t
990load_thread(
991 struct thread_command *tcp,
91447636 992 thread_t thread,
1c79356b
A
993 load_result_t *result
994)
995{
1c79356b
A
996 kern_return_t kret;
997 load_return_t lret;
0b4e3aa0
A
998 task_t task;
999 int customstack=0;
1c79356b 1000
55e303ae 1001 task = get_threadtask(thread);
0b4e3aa0
A
1002
1003 /* if count is 0; same as thr_act */
1004 if (result->thread_count != 0) {
1005 kret = thread_create(task, &thread);
1c79356b
A
1006 if (kret != KERN_SUCCESS)
1007 return(LOAD_RESOURCE);
91447636 1008 thread_deallocate(thread);
1c79356b
A
1009 }
1010
1011 lret = load_threadstate(thread,
1012 (unsigned long *)(((vm_offset_t)tcp) +
1013 sizeof(struct thread_command)),
1014 tcp->cmdsize - sizeof(struct thread_command));
1015 if (lret != LOAD_SUCCESS)
1016 return (lret);
1017
1018 if (result->thread_count == 0) {
0b4e3aa0 1019 lret = load_threadstack(thread,
1c79356b
A
1020 (unsigned long *)(((vm_offset_t)tcp) +
1021 sizeof(struct thread_command)),
1022 tcp->cmdsize - sizeof(struct thread_command),
0b4e3aa0
A
1023 &result->user_stack,
1024 &customstack);
1025 if (customstack)
1026 result->customstack = 1;
1027 else
1028 result->customstack = 0;
1029
1c79356b
A
1030 if (lret != LOAD_SUCCESS)
1031 return(lret);
1032
0b4e3aa0 1033 lret = load_threadentry(thread,
1c79356b
A
1034 (unsigned long *)(((vm_offset_t)tcp) +
1035 sizeof(struct thread_command)),
1036 tcp->cmdsize - sizeof(struct thread_command),
1037 &result->entry_point);
1038 if (lret != LOAD_SUCCESS)
1039 return(lret);
1040 }
1041 /*
1042 * Resume thread now, note that this means that the thread
1043 * commands should appear after all the load commands to
1044 * be sure they don't reference anything not yet mapped.
1045 */
1046 else
1047 thread_resume(thread);
1048
1049 result->thread_count++;
1050
1051 return(LOAD_SUCCESS);
1052}
1053
91447636
A
1054static
1055load_return_t
1056load_unixthread(
1057 struct thread_command *tcp,
1058 thread_t thread,
1059 load_result_t *result
1060)
1061{
1062 load_return_t ret;
1063 int customstack =0;
1064
1065 if (result->thread_count != 0)
1066 return (LOAD_FAILURE);
1067
1068 ret = load_threadstack(thread,
1069 (unsigned long *)(((vm_offset_t)tcp) +
1070 sizeof(struct thread_command)),
1071 tcp->cmdsize - sizeof(struct thread_command),
1072 &result->user_stack,
1073 &customstack);
1074 if (ret != LOAD_SUCCESS)
1075 return(ret);
1076
1077 if (customstack)
1078 result->customstack = 1;
1079 else
1080 result->customstack = 0;
1081 ret = load_threadentry(thread,
1082 (unsigned long *)(((vm_offset_t)tcp) +
1083 sizeof(struct thread_command)),
1084 tcp->cmdsize - sizeof(struct thread_command),
1085 &result->entry_point);
1086 if (ret != LOAD_SUCCESS)
1087 return(ret);
1088
1089 ret = load_threadstate(thread,
1090 (unsigned long *)(((vm_offset_t)tcp) +
1091 sizeof(struct thread_command)),
1092 tcp->cmdsize - sizeof(struct thread_command));
1093 if (ret != LOAD_SUCCESS)
1094 return (ret);
1095
1096 result->unixproc = TRUE;
1097 result->thread_count++;
1098
1099 return(LOAD_SUCCESS);
1100}
1101
1c79356b
A
1102static
1103load_return_t
1104load_threadstate(
1105 thread_t thread,
1106 unsigned long *ts,
1107 unsigned long total_size
1108)
1109{
1110 kern_return_t ret;
1111 unsigned long size;
1112 int flavor;
91447636 1113 unsigned long thread_size;
1c79356b 1114
91447636
A
1115 ret = thread_state_initialize( thread );
1116 if (ret != KERN_SUCCESS)
1117 return(LOAD_FAILURE);
1118
1c79356b 1119 /*
91447636
A
1120 * Set the new thread state; iterate through the state flavors in
1121 * the mach-o file.
1c79356b 1122 */
1c79356b
A
1123 while (total_size > 0) {
1124 flavor = *ts++;
1125 size = *ts++;
91447636
A
1126 thread_size = (size+2)*sizeof(unsigned long);
1127 if (thread_size > total_size)
1c79356b 1128 return(LOAD_BADMACHO);
91447636
A
1129 total_size -= thread_size;
1130 /*
1131 * Third argument is a kernel space pointer; it gets cast
1132 * to the appropriate type in machine_thread_set_state()
1133 * based on the value of flavor.
1134 */
1135 ret = thread_setstatus(thread, flavor, (thread_state_t)ts, size);
1c79356b
A
1136 if (ret != KERN_SUCCESS)
1137 return(LOAD_FAILURE);
1138 ts += size; /* ts is a (unsigned long *) */
1139 }
1140 return(LOAD_SUCCESS);
1141}
1142
1143static
1144load_return_t
1145load_threadstack(
1146 thread_t thread,
1147 unsigned long *ts,
1148 unsigned long total_size,
91447636 1149 user_addr_t *user_stack,
0b4e3aa0 1150 int *customstack
1c79356b
A
1151)
1152{
1153 kern_return_t ret;
1154 unsigned long size;
1155 int flavor;
91447636 1156 unsigned long stack_size;
1c79356b 1157
1c79356b
A
1158 while (total_size > 0) {
1159 flavor = *ts++;
1160 size = *ts++;
91447636
A
1161 stack_size = (size+2)*sizeof(unsigned long);
1162 if (stack_size > total_size)
1c79356b 1163 return(LOAD_BADMACHO);
91447636
A
1164 total_size -= stack_size;
1165
1166 /*
1167 * Third argument is a kernel space pointer; it gets cast
1168 * to the appropriate type in thread_userstack() based on
1169 * the value of flavor.
1170 */
1171 ret = thread_userstack(thread, flavor, (thread_state_t)ts, size, user_stack, customstack);
1c79356b
A
1172 if (ret != KERN_SUCCESS)
1173 return(LOAD_FAILURE);
1174 ts += size; /* ts is a (unsigned long *) */
1175 }
1176 return(LOAD_SUCCESS);
1177}
1178
1179static
1180load_return_t
1181load_threadentry(
1182 thread_t thread,
1183 unsigned long *ts,
1184 unsigned long total_size,
91447636 1185 mach_vm_offset_t *entry_point
1c79356b
A
1186)
1187{
1188 kern_return_t ret;
1189 unsigned long size;
1190 int flavor;
91447636 1191 unsigned long entry_size;
1c79356b
A
1192
1193 /*
1194 * Set the thread state.
1195 */
91447636 1196 *entry_point = MACH_VM_MIN_ADDRESS;
1c79356b
A
1197 while (total_size > 0) {
1198 flavor = *ts++;
1199 size = *ts++;
91447636
A
1200 entry_size = (size+2)*sizeof(unsigned long);
1201 if (entry_size > total_size)
1c79356b 1202 return(LOAD_BADMACHO);
91447636
A
1203 total_size -= entry_size;
1204 /*
1205 * Third argument is a kernel space pointer; it gets cast
1206 * to the appropriate type in thread_entrypoint() based on
1207 * the value of flavor.
1208 */
1209 ret = thread_entrypoint(thread, flavor, (thread_state_t)ts, size, entry_point);
1c79356b
A
1210 if (ret != KERN_SUCCESS)
1211 return(LOAD_FAILURE);
1212 ts += size; /* ts is a (unsigned long *) */
1213 }
1214 return(LOAD_SUCCESS);
1215}
1216
1c79356b
A
1217
1218static
1219load_return_t
1220load_dylinker(
1221 struct dylinker_command *lcp,
91447636 1222 integer_t archbits,
1c79356b 1223 vm_map_t map,
91447636 1224 thread_t thr_act,
1c79356b 1225 int depth,
55e303ae 1226 load_result_t *result,
c0fea474
A
1227 boolean_t clean_regions,
1228 boolean_t is_64bit
1c79356b
A
1229)
1230{
1231 char *name;
1232 char *p;
1233 struct vnode *vp;
1234 struct mach_header header;
91447636
A
1235 off_t file_offset;
1236 off_t macho_size;
1c79356b
A
1237 vm_map_t copy_map;
1238 load_result_t myresult;
1239 kern_return_t ret;
1240 vm_map_copy_t tmp;
91447636
A
1241 mach_vm_offset_t dyl_start, map_addr;
1242 mach_vm_size_t dyl_length;
1c79356b
A
1243
1244 name = (char *)lcp + lcp->name.offset;
1245 /*
1246 * Check for a proper null terminated string.
1247 */
1248 p = name;
1249 do {
1250 if (p >= (char *)lcp + lcp->cmdsize)
1251 return(LOAD_BADMACHO);
1252 } while (*p++);
1253
91447636 1254 ret = get_macho_vnode(name, archbits, &header, &file_offset, &macho_size, &vp);
1c79356b
A
1255 if (ret)
1256 return (ret);
1257
1c79356b
A
1258 /*
1259 * Load the Mach-O.
91447636 1260 * Use a temporary map to do the work.
1c79356b 1261 */
c0fea474
A
1262 copy_map = vm_map_create(pmap_create(vm_map_round_page(macho_size),
1263 is_64bit),
91447636
A
1264 get_map_min(map), get_map_max(map), TRUE);
1265 if (VM_MAP_NULL == copy_map) {
1266 ret = LOAD_RESOURCE;
1267 goto out;
1268 }
1269
1270 myresult = load_result_null;
1c79356b 1271
0b4e3aa0 1272 ret = parse_machfile(vp, copy_map, thr_act, &header,
1c79356b 1273 file_offset, macho_size,
91447636 1274 FALSE, clean_regions, depth, &myresult);
1c79356b
A
1275
1276 if (ret)
1277 goto out;
1278
1279 if (get_map_nentries(copy_map) > 0) {
1280
91447636
A
1281 dyl_start = mach_get_vm_start(copy_map);
1282 dyl_length = mach_get_vm_end(copy_map) - dyl_start;
1c79356b
A
1283
1284 map_addr = dyl_start;
91447636 1285 ret = mach_vm_allocate(map, &map_addr, dyl_length, VM_FLAGS_FIXED);
1c79356b 1286 if (ret != KERN_SUCCESS) {
91447636 1287 ret = mach_vm_allocate(map, &map_addr, dyl_length, VM_FLAGS_ANYWHERE);
1c79356b
A
1288 }
1289
1290 if (ret != KERN_SUCCESS) {
1291 ret = LOAD_NOSPACE;
1292 goto out;
1293
1294 }
91447636
A
1295 ret = vm_map_copyin(copy_map,
1296 (vm_map_address_t)dyl_start,
1297 (vm_map_size_t)dyl_length,
1298 TRUE, &tmp);
1c79356b
A
1299 if (ret != KERN_SUCCESS) {
1300 (void) vm_map_remove(map,
91447636
A
1301 vm_map_trunc_page(map_addr),
1302 vm_map_round_page(map_addr + dyl_length),
1303 VM_MAP_NO_FLAGS);
1c79356b
A
1304 goto out;
1305 }
1306
91447636
A
1307 ret = vm_map_copy_overwrite(map,
1308 (vm_map_address_t)map_addr,
1309 tmp, FALSE);
1c79356b 1310 if (ret != KERN_SUCCESS) {
91447636
A
1311 vm_map_copy_discard(tmp);
1312 (void) vm_map_remove(map,
1313 vm_map_trunc_page(map_addr),
1314 vm_map_round_page(map_addr + dyl_length),
1315 VM_MAP_NO_FLAGS);
1316 goto out;
1317 }
1c79356b
A
1318
1319 if (map_addr != dyl_start)
1320 myresult.entry_point += (map_addr - dyl_start);
1321 } else
1322 ret = LOAD_FAILURE;
1323
1324 if (ret == LOAD_SUCCESS) {
1325 result->dynlinker = TRUE;
1326 result->entry_point = myresult.entry_point;
91447636 1327 (void)ubc_map(vp, PROT_EXEC);
1c79356b
A
1328 }
1329out:
1330 vm_map_deallocate(copy_map);
1331
91447636 1332 vnode_put(vp);
1c79356b
A
1333 return (ret);
1334
1335}
1336
91447636
A
1337/*
1338 * This routine exists to support the load_dylinker().
1339 *
1340 * This routine has its own, separate, understanding of the FAT file format,
1341 * which is terrifically unfortunate.
1342 */
1c79356b
A
1343static
1344load_return_t
1345get_macho_vnode(
1346 char *path,
91447636 1347 integer_t archbits,
1c79356b 1348 struct mach_header *mach_header,
91447636
A
1349 off_t *file_offset,
1350 off_t *macho_size,
1c79356b
A
1351 struct vnode **vpp
1352)
1353{
1354 struct vnode *vp;
91447636 1355 struct vfs_context context;
1c79356b
A
1356 struct nameidata nid, *ndp;
1357 struct proc *p = current_proc(); /* XXXX */
1358 boolean_t is_fat;
1359 struct fat_arch fat_arch;
55e303ae 1360 int error = LOAD_SUCCESS;
1c79356b
A
1361 int resid;
1362 union {
1363 struct mach_header mach_header;
1364 struct fat_header fat_header;
1365 char pad[512];
1366 } header;
0b4e3aa0 1367 off_t fsize = (off_t)0;
91447636 1368 struct ucred *cred = kauth_cred_get();
55e303ae 1369 int err2;
1c79356b 1370
91447636
A
1371 context.vc_proc = p;
1372 context.vc_ucred = cred;
1373
1c79356b 1374 ndp = &nid;
1c79356b
A
1375
1376 /* init the namei data to point the file user's program name */
91447636 1377 NDINIT(ndp, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE32, CAST_USER_ADDR_T(path), &context);
1c79356b 1378
91447636 1379 if ((error = namei(ndp)) != 0) {
55e303ae
A
1380 if (error == ENOENT)
1381 error = LOAD_ENOENT;
1382 else
1383 error = LOAD_FAILURE;
1c79356b 1384 return(error);
55e303ae 1385 }
91447636 1386 nameidone(ndp);
1c79356b
A
1387 vp = ndp->ni_vp;
1388
1389 /* check for regular file */
1390 if (vp->v_type != VREG) {
55e303ae 1391 error = LOAD_PROTECT;
1c79356b
A
1392 goto bad1;
1393 }
1394
91447636
A
1395 /* get size */
1396 if ((error = vnode_size(vp, &fsize, &context)) != 0) {
55e303ae 1397 error = LOAD_FAILURE;
1c79356b 1398 goto bad1;
55e303ae 1399 }
1c79356b
A
1400
1401 /* Check mount point */
1402 if (vp->v_mount->mnt_flag & MNT_NOEXEC) {
55e303ae 1403 error = LOAD_PROTECT;
1c79356b
A
1404 goto bad1;
1405 }
1406
91447636
A
1407 /* check access */
1408 if ((error = vnode_authorize(vp, NULL, KAUTH_VNODE_EXECUTE, &context)) != 0) {
55e303ae 1409 error = LOAD_PROTECT;
1c79356b 1410 goto bad1;
55e303ae 1411 }
0b4e3aa0 1412
1c79356b 1413 /* try to open it */
91447636 1414 if ((error = VNOP_OPEN(vp, FREAD, &context)) != 0) {
55e303ae 1415 error = LOAD_PROTECT;
1c79356b 1416 goto bad1;
0b4e3aa0
A
1417 }
1418
91447636
A
1419 if ((error = vn_rdwr(UIO_READ, vp, (caddr_t)&header, sizeof(header), 0,
1420 UIO_SYSSPACE32, IO_NODELOCKED, cred, &resid, p)) != 0) {
55e303ae 1421 error = LOAD_IOERROR;
1c79356b 1422 goto bad2;
55e303ae 1423 }
1c79356b 1424
91447636
A
1425 if (header.mach_header.magic == MH_MAGIC ||
1426 header.mach_header.magic == MH_MAGIC_64)
1c79356b
A
1427 is_fat = FALSE;
1428 else if (header.fat_header.magic == FAT_MAGIC ||
1429 header.fat_header.magic == FAT_CIGAM)
1430 is_fat = TRUE;
1431 else {
1432 error = LOAD_BADMACHO;
1433 goto bad2;
1434 }
1435
1436 if (is_fat) {
0b4e3aa0 1437 /* Look up our architecture in the fat file. */
91447636 1438 error = fatfile_getarch_with_bits(vp, archbits, (vm_offset_t)(&header.fat_header), &fat_arch);
0b4e3aa0 1439 if (error != LOAD_SUCCESS)
1c79356b 1440 goto bad2;
0b4e3aa0
A
1441
1442 /* Read the Mach-O header out of it */
55e303ae 1443 error = vn_rdwr(UIO_READ, vp, (caddr_t)&header.mach_header,
1c79356b 1444 sizeof(header.mach_header), fat_arch.offset,
91447636 1445 UIO_SYSSPACE32, IO_NODELOCKED, cred, &resid, p);
1c79356b 1446 if (error) {
55e303ae 1447 error = LOAD_IOERROR;
1c79356b
A
1448 goto bad2;
1449 }
1450
0b4e3aa0 1451 /* Is this really a Mach-O? */
91447636
A
1452 if (header.mach_header.magic != MH_MAGIC &&
1453 header.mach_header.magic != MH_MAGIC_64) {
1c79356b
A
1454 error = LOAD_BADMACHO;
1455 goto bad2;
1456 }
0b4e3aa0 1457
1c79356b 1458 *file_offset = fat_arch.offset;
0b4e3aa0 1459 *macho_size = fsize = fat_arch.size;
1c79356b 1460 } else {
91447636
A
1461 /*
1462 * Force get_macho_vnode() to fail if the architecture bits
1463 * do not match the expected architecture bits. This in
1464 * turn causes load_dylinker() to fail for the same reason,
1465 * so it ensures the dynamic linker and the binary are in
1466 * lock-step. This is potentially bad, if we ever add to
1467 * the CPU_ARCH_* bits any bits that are desirable but not
1468 * required, since the dynamic linker might work, but we will
1469 * refuse to load it because of this check.
1470 */
1471 if ((cpu_type_t)(header.mach_header.cputype & CPU_ARCH_MASK) != archbits)
1472 return(LOAD_BADARCH);
0b4e3aa0 1473
1c79356b 1474 *file_offset = 0;
91447636 1475 *macho_size = fsize;
1c79356b
A
1476 }
1477
0b4e3aa0
A
1478 *mach_header = header.mach_header;
1479 *vpp = vp;
91447636
A
1480
1481 ubc_setsize(vp, fsize);
0b4e3aa0 1482
0b4e3aa0
A
1483 return (error);
1484
1c79356b 1485bad2:
91447636
A
1486 err2 = VNOP_CLOSE(vp, FREAD, &context);
1487 vnode_put(vp);
1c79356b 1488 return (error);
0b4e3aa0 1489
1c79356b 1490bad1:
91447636 1491 vnode_put(vp);
1c79356b
A
1492 return(error);
1493}