|
|
1.1 root 1: /*
2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7: * Reserved. This file contains Original Code and/or Modifications of
8: * Original Code as defined in and that are subject to the Apple Public
9: * Source License Version 1.1 (the "License"). You may not use this file
10: * except in compliance with the License. Please obtain a copy of the
11: * License at http://www.apple.com/publicsource and read it before using
12: * this file.
13: *
14: * The Original Code and all software distributed under the License are
15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19: * License for the specific language governing rights and limitations
20: * under the License.
21: *
22: * @APPLE_LICENSE_HEADER_END@
23: */
24:
25: /*
26: * Copyright (C) 1988, 1989, NeXT, Inc.
27: *
28: * File: kern/mach_loader.c
29: * Author: Avadis Tevanian, Jr.
30: *
31: * Mach object file loader (kernel version, for now).
32: *
33: * 21-Jul-88 Avadis Tevanian, Jr. (avie) at NeXT
34: * Started.
35: */
36: #import <mach_nbc.h>
37: #import <sys/param.h>
38: #import <sys/vnode.h>
39: #import <sys/uio.h>
40: #import <sys/namei.h>
41: #import <sys/proc.h>
42: #import <sys/stat.h>
43: #import <sys/malloc.h>
44: #import <sys/mount.h>
45: #import <sys/fcntl.h>
46:
47: #include <ufs/ufs/lockf.h>
48: #include <ufs/ufs/quota.h>
49: #include <ufs/ufs/inode.h>
50:
51: #import <mach/mach_types.h>
52:
53: #import <kern/mach_loader.h>
54: #import <kern/mapfs.h>
55:
56: #import <mach-o/fat.h>
57: #import <mach-o/loader.h>
58:
59: #import <bsd/machine/cpu.h>
60:
61: #import <vm/vm_kern.h>
62: #import <vm/vm_pager.h>
63: #import <vm/vnode_pager.h>
64:
65: /*
66: * Prototypes of static functions.
67: */
68: static
69: load_return_t
70: parse_machfile(
71: struct vnode *vp,
72: vm_map_t map,
73: struct mach_header *header,
74: unsigned long file_offset,
75: unsigned long macho_size,
76: int depth,
77: unsigned long *lib_version,
78: load_result_t *result
79: ),
80: load_segment(
81: struct segment_command *scp,
82: vm_pager_t pager,
83: unsigned long pager_offset,
84: unsigned long macho_size,
85: unsigned long end_of_file,
86: vm_map_t map,
87: load_result_t *result
88: ),
89: load_unixthread(
90: struct thread_command *tcp,
91: load_result_t *result
92: ),
93: load_thread(
94: struct thread_command *tcp,
95: load_result_t *result
96: ),
97: load_threadstate(
98: thread_t thread,
99: unsigned long *ts,
100: unsigned long total_size
101: ),
102: load_threadstack(
103: thread_t thread,
104: unsigned long *ts,
105: unsigned long total_size,
106: vm_offset_t *user_stack
107: ),
108: load_threadentry(
109: thread_t thread,
110: unsigned long *ts,
111: unsigned long total_size,
112: vm_offset_t *entry_point
113: ),
114: load_fvmlib(
115: struct fvmlib_command *lcp,
116: vm_map_t map,
117: int depth
118: ),
119: load_idfvmlib(
120: struct fvmlib_command *lcp,
121: unsigned long *version
122: ),
123: load_dylinker(
124: struct dylinker_command *lcp,
125: vm_map_t map,
126: int depth,
127: load_result_t *result
128: ),
129: get_macho_vnode(
130: char *path,
131: struct mach_header *mach_header,
132: unsigned long *file_offset,
133: unsigned long *macho_size,
134: struct vnode **vpp
135: );
136:
137: load_return_t
138: load_machfile(
139: struct vnode *vp,
140: struct mach_header *header,
141: unsigned long file_offset,
142: unsigned long macho_size,
143: load_result_t *result
144: )
145: {
146: pmap_t pmap;
147: vm_map_t map;
148: vm_map_t old_map;
149: load_result_t myresult;
150: kern_return_t kret;
151: load_return_t lret;
152:
153: old_map = current_task()->map;
154: pmap = old_map->pmap;
155: pmap_reference(pmap);
156: map = vm_map_create(pmap,
157: old_map->min_offset,
158: old_map->max_offset,
159: old_map->hdr.entries_pageable);
160:
161: if (!result)
162: result = &myresult;
163:
164: *result = (load_result_t) { 0 };
165:
166: lret = parse_machfile(vp, map, header, file_offset, macho_size,
167: 0, (unsigned long *)0, result);
168:
169: if (lret != LOAD_SUCCESS) {
170: vm_map_deallocate(map); /* will lose pmap reference too */
171: return(lret);
172: }
173: /*
174: * Commit to new map, destroy old map. (Destruction
175: * of old map cleans up pmap data structures too).
176: */
177: current_task()->map = map;
178: vm_map_deallocate(old_map);
179:
180: return(LOAD_SUCCESS);
181: }
182:
183: static
184: load_return_t
185: parse_machfile(
186: struct vnode *vp,
187: vm_map_t map,
188: struct mach_header *header,
189: unsigned long file_offset,
190: unsigned long macho_size,
191: int depth,
192: unsigned long *lib_version,
193: load_result_t *result
194: )
195: {
196: struct machine_slot *ms;
197: int ncmds;
198: struct load_command *lcp, *next;
199: struct dylinker_command *dlp = 0;
200: vm_pager_t pager;
201: load_return_t ret;
202: vm_offset_t addr;
203: vm_size_t size;
204: int offset;
205: int pass;
206:
207: /*
208: * Break infinite recursion
209: */
210: if (depth > 6)
211: return(LOAD_FAILURE);
212: depth++;
213:
214: /*
215: * Check to see if right machine type.
216: */
217: ms = &machine_slot[cpu_number()];
218: if ((header->cputype != ms->cpu_type) ||
219: !check_cpu_subtype(header->cpusubtype))
220: return(LOAD_BADARCH);
221:
222: switch (header->filetype) {
223:
224: case MH_OBJECT:
225: case MH_EXECUTE:
226: case MH_PRELOAD:
227: if (depth != 1)
228: return (LOAD_FAILURE);
229: break;
230:
231: case MH_FVMLIB:
232: case MH_DYLIB:
233: if (depth == 1)
234: return (LOAD_FAILURE);
235: break;
236:
237: case MH_DYLINKER:
238: if (depth != 2)
239: return (LOAD_FAILURE);
240: break;
241:
242: default:
243: return (LOAD_FAILURE);
244: }
245:
246: /*
247: * Get the pager for the file.
248: */
249: pager = (vm_pager_t) vnode_pager_setup(vp, FALSE, TRUE);
250:
251: /*
252: * Map portion that must be accessible directly into
253: * kernel's map.
254: */
255: if ((sizeof (struct mach_header) + header->sizeofcmds) > macho_size)
256: return(LOAD_BADMACHO);
257:
258: /*
259: * Round size of Mach-O commands up to page boundry.
260: */
261: size = round_page(sizeof (struct mach_header) + header->sizeofcmds);
262: if (size <= 0)
263: return(LOAD_BADMACHO);
264:
265: /*
266: * Map the load commands into kernel memory.
267: */
268: addr = 0;
269: ret = vm_allocate_with_pager(kernel_map, &addr, size, TRUE, pager,
270: file_offset);
271: if (ret != KERN_SUCCESS) {
272: return(LOAD_NOSPACE);
273: }
274:
275: /*
276: * Scan through the commands, processing each one as necessary.
277: */
278: for (pass = 1; pass <= 2; pass++) {
279: offset = sizeof(struct mach_header);
280: ncmds = header->ncmds;
281: while (ncmds--) {
282: /*
283: * Get a pointer to the command.
284: */
285: lcp = (struct load_command *)(addr + offset);
286: offset += lcp->cmdsize;
287:
288: /*
289: * Check for valid lcp pointer by checking
290: * next offset.
291: */
292: if (offset > header->sizeofcmds
293: + sizeof(struct mach_header)) {
294: vm_map_remove(kernel_map, addr, addr + size);
295: return(LOAD_BADMACHO);
296: }
297:
298: /*
299: * Check for valid command.
300: */
301: switch(lcp->cmd) {
302: case LC_SEGMENT:
303: if (pass != 1)
304: break;
305: ret = load_segment(
306: (struct segment_command *) lcp,
307: pager, file_offset,
308: macho_size,
309: vp->v_vm_info->vnode_size,
310: map,
311: result);
312: break;
313: case LC_THREAD:
314: if (pass != 2)
315: break;
316: ret = load_thread((struct thread_command *)lcp,
317: result);
318: break;
319: case LC_UNIXTHREAD:
320: if (pass != 2)
321: break;
322: ret = load_unixthread(
323: (struct thread_command *) lcp,
324: result);
325: break;
326: case LC_LOADFVMLIB:
327: if (pass != 1)
328: break;
329: ret = load_fvmlib((struct fvmlib_command *)lcp,
330: map, depth);
331: break;
332: case LC_IDFVMLIB:
333: if (pass != 1)
334: break;
335: if (lib_version) {
336: ret = load_idfvmlib(
337: (struct fvmlib_command *)lcp,
338: lib_version);
339: }
340: break;
341: case LC_LOAD_DYLINKER:
342: if (pass != 2)
343: break;
344: if (depth == 1 || dlp == 0)
345: dlp = (struct dylinker_command *)lcp;
346: else
347: ret = LOAD_FAILURE;
348: break;
349: default:
350: ret = KERN_SUCCESS;/* ignore other stuff */
351: }
352: if (ret != LOAD_SUCCESS)
353: break;
354: }
355: if (ret != LOAD_SUCCESS)
356: break;
357: }
358: if (ret == LOAD_SUCCESS && dlp != 0)
359: ret = load_dylinker(dlp, map, depth, result);
360:
361: vm_map_remove(kernel_map, addr, addr + size);
362: if ((ret == LOAD_SUCCESS) && (depth == 1) &&
363: (result->thread_count == 0))
364: ret = LOAD_FAILURE;
365: return(ret);
366: }
367:
368: static
369: load_return_t load_segment(
370: struct segment_command *scp,
371: vm_pager_t pager,
372: unsigned long pager_offset,
373: unsigned long macho_size,
374: unsigned long end_of_file,
375: vm_map_t map,
376: load_result_t *result
377: )
378: {
379: int vmsize, copyoffset, copysize;
380: kern_return_t ret;
381: vm_offset_t dest_addr, src_addr;
382: vm_map_t temp_map;
383:
384: /*
385: * Make sure what we get from the file is really ours (as specified
386: * by macho_size).
387: */
388: if (scp->fileoff + scp->filesize > macho_size)
389: return (LOAD_BADMACHO);
390:
391: /*
392: * Round segment size to page size and check validity.
393: */
394: vmsize = round_page(scp->vmsize);
395: if (vmsize < 0)
396: return(LOAD_BADMACHO);
397:
398: if (vmsize == 0)
399: return(KERN_SUCCESS);
400:
401: /*
402: * Truncate address to page boundry and check validity
403: * by allocating the space in the map.
404: */
405: dest_addr = trunc_page(scp->vmaddr);
406: ret = vm_map_find(map, VM_OBJECT_NULL, (vm_offset_t)0,
407: &dest_addr, vmsize, FALSE);
408:
409: if (ret != KERN_SUCCESS)
410: return(LOAD_NOSPACE);
411:
412: /*
413: * Map file into a temporary map.
414: */
415: copysize = round_page(scp->filesize);
416: copyoffset = scp->fileoff + pager_offset;
417:
418: if (copysize < 0)
419: return(LOAD_BADMACHO);
420:
421: if (copysize > 0) {
422: temp_map = vm_map_create(pmap_create(copysize),
423: VM_MIN_ADDRESS, VM_MIN_ADDRESS + copysize,
424: TRUE);
425: src_addr = VM_MIN_ADDRESS;
426: ret = vm_allocate_with_pager(temp_map, &src_addr, copysize,
427: FALSE, pager, copyoffset);
428: if (ret != KERN_SUCCESS) {
429: vm_map_deallocate(temp_map);
430: return(LOAD_NOSPACE);
431: }
432:
433: /*
434: * If last page is not complete, we need to zero fill
435: * it.
436: *
437: * OPTIMIZATION:
438: * If we have a pointer to the vnode we are paging
439: * from, we can optimize the zero-fill if we are at
440: * the end-of-file because the vnode pager semantics
441: * assure that bytes after the end-of-file will be zero.
442: *
443: * FIXME:
444: * Figure out if we can optimize away zeroing the end
445: * of a Mach-O within a fat file.
446: *
447: */
448: if (copysize != scp->filesize
449: && (end_of_file == 0
450: || copyoffset + scp->filesize != end_of_file)) {
451: vm_offset_t tmp_addr;
452: int trunc_addr;
453:
454: trunc_addr = trunc_page(scp->filesize);
455: /*
456: * Allocate some space accessible to the kernel.
457: */
458: tmp_addr = 0;
459: ret = vm_map_find(kernel_map, VM_OBJECT_NULL,
460: (vm_offset_t)0, &tmp_addr,
461: PAGE_SIZE, TRUE);
462: if (ret != KERN_SUCCESS) {
463: vm_map_deallocate(temp_map);
464: return(LOAD_NOSPACE);
465: }
466: /*
467: * Copy last page into kernel.
468: */
469: ret = vm_map_copy(kernel_map, temp_map,
470: tmp_addr, PAGE_SIZE, trunc_addr,
471: FALSE, FALSE);
472: if (ret != KERN_SUCCESS) {
473: vm_deallocate(kernel_map, tmp_addr, PAGE_SIZE);
474: vm_map_deallocate(temp_map);
475: return(LOAD_FAILURE);
476: }
477: /*
478: * Zero appropriate bytes in copy-on-write copy.
479: */
480: bzero(tmp_addr + (scp->filesize - trunc_addr),
481: copysize - scp->filesize);
482: /*
483: * Copy new data back to user task map.
484: */
485: ret = vm_map_copy(map, kernel_map,
486: dest_addr + trunc_addr, PAGE_SIZE, tmp_addr,
487: FALSE, FALSE);
488: vm_deallocate(kernel_map, tmp_addr, PAGE_SIZE);
489: if (ret != KERN_SUCCESS) {
490: vm_map_deallocate(temp_map);
491: return(LOAD_FAILURE);
492: }
493:
494: /*
495: * Adjust copysize for correct copy below.
496: */
497: copysize = trunc_addr;
498: }
499:
500: /*
501: * Copy the data into map.
502: */
503: ret = vm_map_copy(map, temp_map, dest_addr, copysize, src_addr,
504: FALSE, FALSE);
505: vm_map_deallocate(temp_map);
506: if (ret != KERN_SUCCESS)
507: return(LOAD_FAILURE);
508: }
509:
510: #if 0
511: /*
512: * Prepage data XXX do this only on a flag.
513: */
514:
515: /*
516: * Touch each page by referencing it.
517: */
518: addr = dest_addr;
519: while (addr < dest_addr + copysize) {
520: (void) vm_fault(map, addr, VM_PROT_READ, FALSE, 0);
521: addr += PAGE_SIZE;
522: }
523: #endif 0
524:
525: /*
526: * Set protection values. (Note: ignore errors!)
527: */
528:
529: if (scp->maxprot != VM_PROT_DEFAULT) {
530: (void) vm_map_protect(map,
531: dest_addr,
532: dest_addr + vmsize,
533: scp->maxprot,
534: TRUE);
535: }
536: if (scp->initprot != VM_PROT_DEFAULT) {
537: (void) vm_map_protect(map,
538: dest_addr,
539: dest_addr + vmsize,
540: scp->initprot,
541: FALSE);
542: }
543: if ( (scp->fileoff == 0) && (scp->filesize != 0) )
544: result->mach_header = dest_addr;
545: return(LOAD_SUCCESS);
546: }
547:
548: static
549: load_return_t
550: load_unixthread(
551: struct thread_command *tcp,
552: load_result_t *result
553: )
554: {
555: thread_t thread = current_thread();
556: load_return_t ret;
557:
558: if (result->thread_count != 0)
559: return (LOAD_FAILURE);
560:
561: ret = load_threadstack(thread,
562: (unsigned long *)(((vm_offset_t)tcp) +
563: sizeof(struct thread_command)),
564: tcp->cmdsize - sizeof(struct thread_command),
565: &result->user_stack);
566: if (ret != LOAD_SUCCESS)
567: return(ret);
568:
569: ret = load_threadentry(thread,
570: (unsigned long *)(((vm_offset_t)tcp) +
571: sizeof(struct thread_command)),
572: tcp->cmdsize - sizeof(struct thread_command),
573: &result->entry_point);
574: if (ret != LOAD_SUCCESS)
575: return(ret);
576:
577: ret = load_threadstate(thread,
578: (unsigned long *)(((vm_offset_t)tcp) +
579: sizeof(struct thread_command)),
580: tcp->cmdsize - sizeof(struct thread_command));
581: if (ret != LOAD_SUCCESS)
582: return (ret);
583:
584: result->unixproc = TRUE;
585: result->thread_count++;
586:
587: return(LOAD_SUCCESS);
588: }
589:
590: static
591: load_return_t
592: load_thread(
593: struct thread_command *tcp,
594: load_result_t *result
595: )
596: {
597: thread_t thread;
598: kern_return_t kret;
599: load_return_t lret;
600:
601: if (result->thread_count == 0)
602: thread = current_thread();
603: else {
604: kret = thread_create(current_task(), &thread);
605: if (kret != KERN_SUCCESS)
606: return(LOAD_RESOURCE);
607: thread_deallocate(thread);
608: }
609:
610: lret = load_threadstate(thread,
611: (unsigned long *)(((vm_offset_t)tcp) +
612: sizeof(struct thread_command)),
613: tcp->cmdsize - sizeof(struct thread_command));
614: if (lret != LOAD_SUCCESS)
615: return (lret);
616:
617: if (result->thread_count == 0) {
618: lret = load_threadstack(current_thread(),
619: (unsigned long *)(((vm_offset_t)tcp) +
620: sizeof(struct thread_command)),
621: tcp->cmdsize - sizeof(struct thread_command),
622: &result->user_stack);
623: if (lret != LOAD_SUCCESS)
624: return(lret);
625:
626: lret = load_threadentry(current_thread(),
627: (unsigned long *)(((vm_offset_t)tcp) +
628: sizeof(struct thread_command)),
629: tcp->cmdsize - sizeof(struct thread_command),
630: &result->entry_point);
631: if (lret != LOAD_SUCCESS)
632: return(lret);
633: }
634: /*
635: * Resume thread now, note that this means that the thread
636: * commands should appear after all the load commands to
637: * be sure they don't reference anything not yet mapped.
638: */
639: else
640: thread_resume(thread);
641:
642: result->thread_count++;
643:
644: return(LOAD_SUCCESS);
645: }
646:
647: static
648: load_return_t
649: load_threadstate(
650: thread_t thread,
651: unsigned long *ts,
652: unsigned long total_size
653: )
654: {
655: kern_return_t ret;
656: unsigned long size;
657: int flavor;
658:
659: /*
660: * Set the thread state.
661: */
662:
663: while (total_size > 0) {
664: flavor = *ts++;
665: size = *ts++;
666: total_size -= (size+2)*sizeof(unsigned long);
667: if (total_size < 0)
668: return(LOAD_BADMACHO);
669: ret = thread_setstatus(thread, flavor, ts, size);
670: if (ret != KERN_SUCCESS)
671: return(LOAD_FAILURE);
672: ts += size; /* ts is a (unsigned long *) */
673: }
674: return(LOAD_SUCCESS);
675: }
676:
677: static
678: load_return_t
679: load_threadstack(
680: thread_t thread,
681: unsigned long *ts,
682: unsigned long total_size,
683: vm_offset_t *user_stack
684: )
685: {
686: kern_return_t ret;
687: unsigned long size;
688: int flavor;
689:
690: /*
691: * Set the thread state.
692: */
693: *user_stack = 0;
694: while (total_size > 0) {
695: flavor = *ts++;
696: size = *ts++;
697: total_size -= (size+2)*sizeof(unsigned long);
698: if (total_size < 0)
699: return(LOAD_BADMACHO);
700: ret = thread_userstack(thread, flavor, ts, size, user_stack);
701: if (ret != KERN_SUCCESS)
702: return(LOAD_FAILURE);
703: ts += size; /* ts is a (unsigned long *) */
704: }
705: return(LOAD_SUCCESS);
706: }
707:
708: static
709: load_return_t
710: load_threadentry(
711: thread_t thread,
712: unsigned long *ts,
713: unsigned long total_size,
714: vm_offset_t *entry_point
715: )
716: {
717: kern_return_t ret;
718: unsigned long size;
719: int flavor;
720:
721: /*
722: * Set the thread state.
723: */
724: *entry_point = 0;
725: while (total_size > 0) {
726: flavor = *ts++;
727: size = *ts++;
728: total_size -= (size+2)*sizeof(unsigned long);
729: if (total_size < 0)
730: return(LOAD_BADMACHO);
731: ret = thread_entrypoint(thread, flavor, ts, size, entry_point);
732: if (ret != KERN_SUCCESS)
733: return(LOAD_FAILURE);
734: ts += size; /* ts is a (unsigned long *) */
735: }
736: return(LOAD_SUCCESS);
737: }
738:
739: static
740: load_return_t
741: load_fvmlib(
742: struct fvmlib_command *lcp,
743: vm_map_t map,
744: int depth
745: )
746: {
747: char *name;
748: char *p;
749: struct vnode *vp;
750: struct mach_header header;
751: unsigned long file_offset;
752: unsigned long macho_size;
753: unsigned long lib_version;
754: load_result_t myresult;
755: kern_return_t ret;
756:
757: name = (char *)lcp + lcp->fvmlib.name.offset;
758: /*
759: * Check for a proper null terminated string.
760: */
761: p = name;
762: do {
763: if (p >= (char *)lcp + lcp->cmdsize)
764: return(LOAD_BADMACHO);
765: } while (*p++);
766:
767: ret = get_macho_vnode(name, &header, &file_offset, &macho_size, &vp);
768: if (ret)
769: return (ret);
770:
771: myresult = (load_result_t) { 0 };
772:
773: /*
774: * Load the Mach-O.
775: */
776: ret = parse_machfile(vp, map, &header,
777: file_offset, macho_size,
778: depth, &lib_version, &myresult);
779:
780: if ((ret == LOAD_SUCCESS) &&
781: (lib_version < lcp->fvmlib.minor_version))
782: ret = LOAD_SHLIB;
783:
784: vrele(vp);
785: return(ret);
786: }
787:
788: static
789: load_return_t
790: load_idfvmlib(
791: struct fvmlib_command *lcp,
792: unsigned long *version
793: )
794: {
795: *version = lcp->fvmlib.minor_version;
796: return(LOAD_SUCCESS);
797: }
798:
799: #if hppa
800: #include <machdep/hppa/thread.h>
801: extern int catch_user_alignment_traps;
802: #endif /* hppa */
803:
804: static
805: load_return_t
806: load_dylinker(
807: struct dylinker_command *lcp,
808: vm_map_t map,
809: int depth,
810: load_result_t *result
811: )
812: {
813: char *name;
814: char *p;
815: struct vnode *vp;
816: struct mach_header header;
817: unsigned long file_offset;
818: unsigned long macho_size;
819: vm_map_t copy_map;
820: load_result_t myresult;
821: kern_return_t ret;
822:
823: name = (char *)lcp + lcp->name.offset;
824: /*
825: * Check for a proper null terminated string.
826: */
827: p = name;
828: do {
829: if (p >= (char *)lcp + lcp->cmdsize)
830: return(LOAD_BADMACHO);
831: } while (*p++);
832:
833: ret = get_macho_vnode(name, &header, &file_offset, &macho_size, &vp);
834: if (ret)
835: return (ret);
836:
837: copy_map = vm_map_create(pmap_create(macho_size),
838: map->min_offset, map->max_offset, TRUE);
839:
840: myresult = (load_result_t) { 0 };
841:
842: /*
843: * Load the Mach-O.
844: */
845: ret = parse_machfile(vp, copy_map, &header,
846: file_offset, macho_size,
847: depth, 0, &myresult);
848: if (ret)
849: goto out;
850:
851: if (copy_map->hdr.nentries > 0) {
852: vm_offset_t dyl_start, map_addr;
853: vm_size_t dyl_length;
854:
855: dyl_start = vm_map_first_entry(copy_map)->vme_start;
856: dyl_length = vm_map_last_entry(copy_map)->vme_end - dyl_start;
857:
858: map_addr = dyl_start;
859: if (vm_map_find(map, VM_OBJECT_NULL, 0,
860: &map_addr, dyl_length, FALSE) &&
861: vm_map_find(map, VM_OBJECT_NULL, 0,
862: &map_addr, dyl_length, TRUE))
863: ret = LOAD_NOSPACE;
864: else if (vm_map_copy(map, copy_map,
865: map_addr, dyl_length, dyl_start,
866: FALSE, FALSE))
867: ret = LOAD_NOSPACE;
868: if (map_addr != dyl_start)
869: myresult.entry_point += (map_addr - dyl_start);
870: }
871: else
872: ret = LOAD_FAILURE;
873:
874: if (ret == LOAD_SUCCESS) {
875: result->dynlinker = TRUE;
876: result->entry_point = myresult.entry_point;
877: #if hppa
878: if (!catch_user_alignment_traps)
879: current_thread()->pcb->pcb_flags |= PCB_ALIGNMENT_FAULT_NO_CATCH;
880: #endif
881: }
882:
883: out:
884: vm_map_deallocate(copy_map);
885:
886: vrele(vp);
887: return (ret);
888: }
889:
890: static
891: load_return_t
892: get_macho_vnode(
893: char *path,
894: struct mach_header *mach_header,
895: unsigned long *file_offset,
896: unsigned long *macho_size,
897: struct vnode **vpp
898: )
899: {
900: struct vnode *vp;
901: struct vattr attr, *atp;
902: struct nameidata nid, *ndp;
903: struct proc *p = current_proc(); /* XXXX */
904: boolean_t is_fat;
905: struct fat_arch fat_arch;
906: int error;
907: int resid;
908: union {
909: struct mach_header mach_header;
910: struct fat_header fat_header;
911: char pad[512];
912: } header;
913: error = KERN_SUCCESS;
914:
915: ndp = &nid;
916: atp = &attr;
917:
918: /* init the namei data to point the file user's program name */
919: NDINIT(ndp, LOOKUP, FOLLOW | LOCKLEAF | SAVENAME, UIO_SYSSPACE, path, p);
920:
921: if (error = namei(ndp))
922: return(error);
923:
924: vp = ndp->ni_vp;
925:
926: /* check for regular file */
927: if (vp->v_type != VREG) {
928: error = EACCES;
929: goto bad1;
930: }
931:
932: /* get attributes */
933: if (error = VOP_GETATTR(vp, &attr, p->p_ucred, p))
934: goto bad1;
935:
936: /* Check mount point */
937: if (vp->v_mount->mnt_flag & MNT_NOEXEC) {
938: error = EACCES;
939: goto bad1;
940: }
941:
942: if ((vp->v_mount->mnt_flag & MNT_NOSUID) || (p->p_flag & P_TRACED))
943: atp->va_mode &= ~(VSUID | VSGID);
944:
945: /* check access. for root we have to see if any exec bit on */
946: if (error = VOP_ACCESS(vp, VEXEC, p->p_ucred, p))
947: goto bad1;
948: if ((atp->va_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) == 0) {
949: error = EACCES;
950: goto bad1;
951: }
952:
953: /* try to open it */
954: if (error = VOP_OPEN(vp, FREAD, p->p_ucred, p))
955: goto bad1;
956: #if MACH_NBC
957: VOP_UNLOCK(vp, 0, p);
958: #endif /* MACH_NBC */
959: if(error = vn_rdwr(UIO_READ, vp, (caddr_t)&header, sizeof(header), 0,
960: UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid, p))
961: goto bad2;
962:
963:
964: /* XXXX WMG - we should check for a short read of the header here */
965:
966: if (header.mach_header.magic == MH_MAGIC)
967: is_fat = FALSE;
968: else if (header.fat_header.magic == FAT_MAGIC ||
969: header.fat_header.magic == FAT_CIGAM)
970: is_fat = TRUE;
971: else {
972: error = LOAD_BADMACHO;
973: goto bad2;
974: }
975:
976: if (is_fat) {
977: /*
978: * Look up our architecture in the fat file.
979: */
980: error = fatfile_getarch(vp, (vm_offset_t)(&header.fat_header), &fat_arch);
981: if (error != LOAD_SUCCESS) {
982: goto bad2;
983: }
984: /*
985: * Read the Mach-O header out of it
986: */
987: error = vn_rdwr(UIO_READ, vp, &header.mach_header,
988: sizeof(header.mach_header), fat_arch.offset,
989: UIO_SYSSPACE, IO_NODELOCKED, p->p_ucred, &resid, p);
990: if (error) {
991: error = LOAD_FAILURE;
992: goto bad2;
993: }
994:
995: /*
996: * Is this really a Mach-O?
997: */
998: if (header.mach_header.magic != MH_MAGIC) {
999: error = LOAD_BADMACHO;
1000: goto bad2;
1001: }
1002:
1003: *mach_header = header.mach_header;
1004: *file_offset = fat_arch.offset;
1005: *macho_size = fat_arch.size;
1006: *vpp = vp;
1007: // leaks otherwise - A.R
1008: FREE_ZONE(ndp->ni_cnd.cn_pnbuf, ndp->ni_cnd.cn_pnlen, M_NAMEI);
1009:
1010: // i_lock exclusive panics, otherwise during pageins
1011: #if !MACH_NBC
1012: VOP_UNLOCK(vp, 0, p);
1013: #endif /* !MACH_NBC */
1014: return (error);
1015: } else {
1016:
1017: *mach_header = header.mach_header;
1018: *file_offset = 0;
1019: if (vp->v_vm_info) {
1020: vp->v_vm_info->vnode_size = attr.va_size;
1021: }
1022: *macho_size = attr.va_size;
1023: *vpp = vp;
1024: // leaks otherwise - A.R
1025: FREE_ZONE(ndp->ni_cnd.cn_pnbuf, ndp->ni_cnd.cn_pnlen, M_NAMEI);
1026:
1027: // i_lock exclusive panics, otherwise during pageins
1028: #if !MACH_NBC
1029: VOP_UNLOCK(vp, 0, p);
1030: #endif /* !MACH_NBC */
1031: return (error);
1032: }
1033:
1034: bad2:
1035: /*
1036: * unlock and close the vnode, restore the old one, free the
1037: * pathname buf, and punt.
1038: */
1039: #if !MACH_NBC
1040: VOP_UNLOCK(vp, 0, p);
1041: #endif /* !MACH_NBC */
1042: vn_close(vp, FREAD, p->p_ucred, p);
1043: FREE_ZONE(ndp->ni_cnd.cn_pnbuf, ndp->ni_cnd.cn_pnlen, M_NAMEI);
1044: return (error);
1045: bad1:
1046: /*
1047: * free the namei pathname buffer, and put the vnode
1048: * (which we don't yet have open).
1049: */
1050: FREE_ZONE(ndp->ni_cnd.cn_pnbuf, ndp->ni_cnd.cn_pnlen, M_NAMEI);
1051: vput(vp);
1052: return(error);
1053: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.