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