|
|
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.