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