X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/813fb2f63a553c957e917ede5f119b021d6ce391..cb3231590a3c94ab4375e2228bd5e86b0cf1ad7e:/libkern/kxld/kxld_object.c diff --git a/libkern/kxld/kxld_object.c b/libkern/kxld/kxld_object.c index f8fc526bc..f83f0f321 100644 --- a/libkern/kxld/kxld_object.c +++ b/libkern/kxld/kxld_object.c @@ -2,7 +2,7 @@ * Copyright (c) 2009-2014 Apple Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ - * + * * This file contains Original Code and/or Modifications of Original Code * as defined in and that are subject to the Apple Public Source License * Version 2.0 (the 'License'). You may not use this file except in @@ -11,10 +11,10 @@ * unlawful or unlicensed copies of an Apple operating system, or to * circumvent, violate, or enable the circumvention or violation of, any * terms of an Apple operating system software license agreement. - * + * * Please obtain a copy of the License at * http://www.opensource.apple.com/apsl/ and read it before using this file. - * + * * The Original Code and all software distributed under the License are * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, @@ -22,7 +22,7 @@ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. * Please see the License for the specific language governing rights and * limitations under the License. - * + * * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ */ #include @@ -34,9 +34,9 @@ #include #include #else /* !KERNEL */ - /* Get machine.h from the kernel source so we can support all platforms - * that the kernel supports. Otherwise we're at the mercy of the host. - */ +/* Get machine.h from the kernel source so we can support all platforms + * that the kernel supports. Otherwise we're at the mercy of the host. + */ #include "../../osfmk/mach/machine.h" #include @@ -48,6 +48,7 @@ #include #include #include +#include #define DEBUG_ASSERT_COMPONENT_NAME_STRING "kxld" #include @@ -75,39 +76,39 @@ extern boolean_t isOldInterface; *******************************************************************************/ struct kxld_object { - u_char *file; // used by old interface - u_long size; // used by old interface - const char *name; - uint32_t filetype; - cpu_type_t cputype; - cpu_subtype_t cpusubtype; - KXLDArray segs; - KXLDArray sects; - KXLDArray extrelocs; - KXLDArray locrelocs; - KXLDRelocator relocator; - KXLDuuid uuid; - KXLDversionmin versionmin; - KXLDsrcversion srcversion; - KXLDSymtab *symtab; - struct dysymtab_command *dysymtab_hdr; - KXLDsplitinfolc splitinfolc; - splitKextLinkInfo split_info; - kxld_addr_t link_addr; - u_long output_buffer_size; - boolean_t is_kernel; - boolean_t is_final_image; - boolean_t is_linked; - boolean_t got_is_created; + u_char *file; // used by old interface + u_long size; // used by old interface + const char *name; + uint32_t filetype; + cpu_type_t cputype; + cpu_subtype_t cpusubtype; + KXLDArray segs; + KXLDArray sects; + KXLDArray extrelocs; + KXLDArray locrelocs; + KXLDRelocator relocator; + KXLDuuid uuid; + KXLDversionmin versionmin; + KXLDsrcversion srcversion; + KXLDSymtab *symtab; + struct dysymtab_command *dysymtab_hdr; + KXLDsplitinfolc splitinfolc; + splitKextLinkInfo split_info; + kxld_addr_t link_addr; + u_long output_buffer_size; + boolean_t is_kernel; + boolean_t is_final_image; + boolean_t is_linked; + boolean_t got_is_created; #if KXLD_USER_OR_OBJECT - KXLDArray *section_order; + KXLDArray *section_order; #endif #if KXLD_PIC_KEXTS - boolean_t include_kaslr_relocs; + boolean_t include_kaslr_relocs; #endif #if !KERNEL - enum NXByteOrder host_order; - enum NXByteOrder target_order; + enum NXByteOrder host_order; + enum NXByteOrder target_order; #endif }; @@ -115,25 +116,25 @@ struct kxld_object { * Prototypes *******************************************************************************/ -static kern_return_t get_target_machine_info(KXLDObject *object, +static kern_return_t get_target_machine_info(KXLDObject *object, cpu_type_t cputype, cpu_subtype_t cpusubtype); -static kern_return_t get_macho_slice_for_arch(KXLDObject *object, +static kern_return_t get_macho_slice_for_arch(KXLDObject *object, u_char *file, u_long size); static u_long get_macho_header_size(const KXLDObject *object); static u_long get_macho_data_size(const KXLDObject *object) __unused; static kern_return_t init_from_execute(KXLDObject *object); -static kern_return_t init_from_final_linked_image(KXLDObject *object, +static kern_return_t init_from_final_linked_image(KXLDObject *object, u_int *filetype_out, struct symtab_command **symtab_hdr_out); static boolean_t target_supports_protected_segments(const KXLDObject *object) - __attribute__((pure)); +__attribute__((pure)); static void set_is_object_linked(KXLDObject *object); #if KXLD_USER_OR_BUNDLE -static boolean_t target_supports_bundle(const KXLDObject *object) - __attribute((pure)); +static boolean_t target_supports_bundle(const KXLDObject *object) +__attribute((pure)); static kern_return_t init_from_bundle(KXLDObject *object); static kern_return_t process_relocs_from_tables(KXLDObject *object); static KXLDSeg *get_seg_by_base_addr(KXLDObject *object, @@ -143,8 +144,8 @@ static void add_to_ptr(u_char *symptr, kxld_addr_t val, boolean_t is_32_bit); #endif /* KXLD_USER_OR_BUNDLE */ #if KXLD_USER_OR_OBJECT -static boolean_t target_supports_object(const KXLDObject *object) - __attribute((pure)); +static boolean_t target_supports_object(const KXLDObject *object) +__attribute((pure)); static kern_return_t init_from_object(KXLDObject *object); static kern_return_t process_relocs_from_sections(KXLDObject *object); #endif /* KXLD_USER_OR_OBJECT */ @@ -154,18 +155,18 @@ static boolean_t target_supports_slideable_kexts(const KXLDObject *object); #endif /* KXLD_PIC_KEXTS */ -static kern_return_t export_macho_header(const KXLDObject *object, u_char *buf, +static kern_return_t export_macho_header(const KXLDObject *object, u_char *buf, u_int ncmds, u_long *header_offset, u_long header_size); #if KXLD_USER_OR_ILP32 -static u_long get_macho_cmd_data_32(u_char *file, u_long offset, +static u_long get_macho_cmd_data_32(u_char *file, u_long offset, u_int *filetype, u_int *ncmds); -static kern_return_t export_macho_header_32(const KXLDObject *object, +static kern_return_t export_macho_header_32(const KXLDObject *object, u_char *buf, u_int ncmds, u_long *header_offset, u_long header_size); #endif /* KXLD_USER_OR_ILP32 */ #if KXLD_USER_OR_LP64 static u_long get_macho_cmd_data_64(u_char *file, u_long offset, u_int *filetype, u_int *ncmds); -static kern_return_t export_macho_header_64(const KXLDObject *object, +static kern_return_t export_macho_header_64(const KXLDObject *object, u_char *buf, u_int ncmds, u_long *header_offset, u_long header_size); #endif /* KXLD_USER_OR_LP64 */ @@ -197,267 +198,273 @@ static KXLDSect * kxld_object_get_sect_by_name(const KXLDObject *object, const c /******************************************************************************* *******************************************************************************/ -size_t +size_t kxld_object_sizeof(void) { - return sizeof(KXLDObject); + return sizeof(KXLDObject); } /******************************************************************************* *******************************************************************************/ -kern_return_t +kern_return_t kxld_object_init_from_macho(KXLDObject *object, u_char *file, u_long size, - const char *name, KXLDArray *section_order __unused, + const char *name, KXLDArray *section_order __unused, cpu_type_t cputype, cpu_subtype_t cpusubtype, KXLDFlags flags __unused) { - kern_return_t rval = KERN_FAILURE; - KXLDSeg * seg = NULL; - u_int i = 0; - u_char * my_file; + kern_return_t rval = KERN_FAILURE; + KXLDSeg * seg = NULL; + u_int i = 0; + u_char * my_file; - check(object); - check(file); - check(name); + check(object); + check(file); + check(name); - object->name = name; + object->name = name; #if KXLD_USER_OR_OBJECT - object->section_order = section_order; + object->section_order = section_order; #endif #if KXLD_PIC_KEXTS - object->include_kaslr_relocs = ((flags & kKXLDFlagIncludeRelocs) == kKXLDFlagIncludeRelocs); + object->include_kaslr_relocs = ((flags & kKXLDFlagIncludeRelocs) == kKXLDFlagIncludeRelocs); #endif - - /* Find the local architecture */ - - rval = get_target_machine_info(object, cputype, cpusubtype); - require_noerr(rval, finish); - - /* Find the Mach-O slice for the target architecture */ - - rval = get_macho_slice_for_arch(object, file, size); - require_noerr(rval, finish); - - if (isOldInterface) { - my_file = object->file; - } - else { - my_file = object->split_info.kextExecutable; - } - - /* Allocate the symbol table */ - - if (!object->symtab) { - object->symtab = kxld_alloc(kxld_symtab_sizeof()); - require_action(object->symtab, finish, rval=KERN_RESOURCE_SHORTAGE); - bzero(object->symtab, kxld_symtab_sizeof()); - } - - /* Build the relocator */ - - rval = kxld_relocator_init(&object->relocator, - my_file, - object->symtab, &object->sects, - object->cputype, - object->cpusubtype, - kxld_object_target_needs_swap(object)); - require_noerr(rval, finish); - - /* There are four types of Mach-O files that we can support: - * 1) 32-bit MH_OBJECT - Snow Leopard and earlier - * 2) 32-bit MH_KEXT_BUNDLE - Lion and Later - * 3) 64-bit MH_OBJECT - Unsupported - * 4) 64-bit MH_KEXT_BUNDLE - Snow Leopard and Later - */ - - if (kxld_object_is_32_bit(object)) { - struct mach_header *mach_hdr = (struct mach_header *) ((void *) my_file); - object->filetype = mach_hdr->filetype; - } else { - struct mach_header_64 *mach_hdr = (struct mach_header_64 *) ((void *) my_file); - object->filetype = mach_hdr->filetype; - } - - switch (object->filetype) { + + /* Find the local architecture */ + + rval = get_target_machine_info(object, cputype, cpusubtype); + require_noerr(rval, finish); + + /* Find the Mach-O slice for the target architecture */ + + rval = get_macho_slice_for_arch(object, file, size); + require_noerr(rval, finish); + + if (isOldInterface) { + my_file = object->file; + } else { + my_file = object->split_info.kextExecutable; + } + + /* Allocate the symbol table */ + + if (!object->symtab) { + object->symtab = kxld_calloc(kxld_symtab_sizeof()); + require_action(object->symtab, finish, rval = KERN_RESOURCE_SHORTAGE); + } + + /* Build the relocator */ + + rval = kxld_relocator_init(&object->relocator, + my_file, + object->symtab, &object->sects, + object->cputype, + object->cpusubtype, + kxld_object_target_needs_swap(object)); + require_noerr(rval, finish); + + /* There are four types of Mach-O files that we can support: + * 1) 32-bit MH_OBJECT - Snow Leopard and earlier + * 2) 32-bit MH_KEXT_BUNDLE - Lion and Later + * 3) 64-bit MH_OBJECT - Unsupported + * 4) 64-bit MH_KEXT_BUNDLE - Snow Leopard and Later + */ + + if (kxld_object_is_32_bit(object)) { + struct mach_header *mach_hdr = (struct mach_header *) ((void *) my_file); + object->filetype = mach_hdr->filetype; + } else { + struct mach_header_64 *mach_hdr = (struct mach_header_64 *) ((void *) my_file); + object->filetype = mach_hdr->filetype; + } + + switch (object->filetype) { #if KXLD_USER_OR_BUNDLE - case MH_KEXT_BUNDLE: - rval = init_from_bundle(object); - require_noerr(rval, finish); - break; + case MH_KEXT_BUNDLE: + rval = init_from_bundle(object); + require_noerr(rval, finish); + break; #endif /* KXLD_USER_OR_BUNDLE */ #if KXLD_USER_OR_OBJECT - case MH_OBJECT: - rval = init_from_object(object); - require_noerr(rval, finish); - break; + case MH_OBJECT: + rval = init_from_object(object); + require_noerr(rval, finish); + break; #endif /* KXLD_USER_OR_OBJECT */ - case MH_EXECUTE: - object->is_kernel = TRUE; - rval = init_from_execute(object); - require_noerr(rval, finish); - break; - default: - rval = KERN_FAILURE; - kxld_log(kKxldLogLinking, kKxldLogErr, - kKxldLogFiletypeNotSupported, object->filetype); - goto finish; - } - - if (!kxld_object_is_kernel(object)) { - for (i = 0; i < object->segs.nitems; ++i) { - seg = kxld_array_get_item(&object->segs, i); - kxld_seg_set_vm_protections(seg, - target_supports_protected_segments(object)); - } - - seg = kxld_object_get_seg_by_name(object, SEG_LINKEDIT); - if (seg) { - (void) kxld_seg_populate_linkedit(seg, object->symtab, - kxld_object_is_32_bit(object) + case MH_EXECUTE: + object->is_kernel = TRUE; + rval = init_from_execute(object); + require_noerr(rval, finish); + break; + default: + rval = KERN_FAILURE; + kxld_log(kKxldLogLinking, kKxldLogErr, + kKxldLogFiletypeNotSupported, object->filetype); + goto finish; + } + + if (!kxld_object_is_kernel(object)) { + for (i = 0; i < object->segs.nitems; ++i) { + seg = kxld_array_get_item(&object->segs, i); + kxld_seg_set_vm_protections(seg, + target_supports_protected_segments(object)); + } + + seg = kxld_object_get_seg_by_name(object, SEG_LINKEDIT); + if (seg) { + (void) kxld_seg_populate_linkedit(seg, object->symtab, + kxld_object_is_32_bit(object) #if KXLD_PIC_KEXTS - , &object->locrelocs, &object->extrelocs, - target_supports_slideable_kexts(object) + , &object->locrelocs, &object->extrelocs, + target_supports_slideable_kexts(object) #endif - , isOldInterface ? 0 : object->splitinfolc.datasize - ); - } - } - - (void) set_is_object_linked(object); - - rval = KERN_SUCCESS; + , isOldInterface ? 0 : object->splitinfolc.datasize + ); + } + } + + (void) set_is_object_linked(object); + + rval = KERN_SUCCESS; finish: - return rval; + return rval; } /******************************************************************************* - *******************************************************************************/ +*******************************************************************************/ splitKextLinkInfo * kxld_object_get_link_info(KXLDObject *object) { - check(object); - - return &object->split_info; + check(object); + + return &object->split_info; } /******************************************************************************* - *******************************************************************************/ +*******************************************************************************/ void kxld_object_set_link_info(KXLDObject *object, splitKextLinkInfo *link_info) { - check(object); - check(link_info); + check(object); + check(link_info); - object->split_info.vmaddr_TEXT = link_info->vmaddr_TEXT; - object->split_info.vmaddr_TEXT_EXEC = link_info->vmaddr_TEXT_EXEC; - object->split_info.vmaddr_DATA = link_info->vmaddr_DATA; - object->split_info.vmaddr_DATA_CONST = link_info->vmaddr_DATA_CONST; - object->split_info.vmaddr_LLVM_COV = link_info->vmaddr_LLVM_COV; - object->split_info.vmaddr_LINKEDIT = link_info->vmaddr_LINKEDIT; + object->split_info.vmaddr_TEXT = link_info->vmaddr_TEXT; + object->split_info.vmaddr_TEXT_EXEC = link_info->vmaddr_TEXT_EXEC; + object->split_info.vmaddr_DATA = link_info->vmaddr_DATA; + object->split_info.vmaddr_DATA_CONST = link_info->vmaddr_DATA_CONST; + object->split_info.vmaddr_LLVM_COV = link_info->vmaddr_LLVM_COV; + object->split_info.vmaddr_LINKEDIT = link_info->vmaddr_LINKEDIT; - return; + return; } /******************************************************************************* *******************************************************************************/ kern_return_t -get_target_machine_info(KXLDObject *object, cpu_type_t cputype __unused, +get_target_machine_info(KXLDObject *object, cpu_type_t cputype __unused, cpu_subtype_t cpusubtype __unused) { #if KERNEL - /* Because the kernel can only link for its own architecture, we know what - * the host and target architectures are at compile time, so we can use - * a vastly simplified version of this function. - */ + /* Because the kernel can only link for its own architecture, we know what + * the host and target architectures are at compile time, so we can use + * a vastly simplified version of this function. + */ - check(object); + check(object); #if defined(__x86_64__) - object->cputype = CPU_TYPE_X86_64; + object->cputype = CPU_TYPE_X86_64; /* FIXME: we need clang to provide a __x86_64h__ macro for the sub-type. Using * __AVX2__ is a temporary solution until this is available. */ #if defined(__AVX2__) - object->cpusubtype = CPU_SUBTYPE_X86_64_H; + object->cpusubtype = CPU_SUBTYPE_X86_64_H; #else - object->cpusubtype = CPU_SUBTYPE_X86_64_ALL; + object->cpusubtype = CPU_SUBTYPE_X86_64_ALL; #endif - return KERN_SUCCESS; -#else - kxld_log(kKxldLogLinking, kKxldLogErr, - kKxldLogArchNotSupported, _mh_execute_header->cputype); - return KERN_NOT_SUPPORTED; + return KERN_SUCCESS; +#elif defined(__arm__) + object->cputype = CPU_TYPE_ARM; + object->cpusubtype = CPU_SUBTYPE_ARM_ALL; + return KERN_SUCCESS; +#elif defined(__arm64__) + object->cputype = CPU_TYPE_ARM64; + object->cpusubtype = CPU_SUBTYPE_ARM64_ALL; + return KERN_SUCCESS; +#else + kxld_log(kKxldLogLinking, kKxldLogErr, + kKxldLogArchNotSupported, _mh_execute_header->cputype); + return KERN_NOT_SUPPORTED; #endif /* Supported architecture defines */ #else /* !KERNEL */ - /* User-space must look up the architecture it's running on and the target - * architecture at run-time. - */ - - kern_return_t rval = KERN_FAILURE; - const NXArchInfo *host_arch = NULL; - - check(object); - - host_arch = NXGetLocalArchInfo(); - require_action(host_arch, finish, rval=KERN_FAILURE); - - object->host_order = host_arch->byteorder; - - /* If the user did not specify a cputype, use the local architecture. - */ - - if (cputype) { - object->cputype = cputype; - object->cpusubtype = cpusubtype; - } else { - object->cputype = host_arch->cputype; - object->target_order = object->host_order; - - switch (object->cputype) { - case CPU_TYPE_I386: - object->cpusubtype = CPU_SUBTYPE_I386_ALL; - break; - case CPU_TYPE_X86_64: - object->cpusubtype = CPU_SUBTYPE_X86_64_ALL; - break; - case CPU_TYPE_ARM: - object->cpusubtype = CPU_SUBTYPE_ARM_ALL; - break; - case CPU_TYPE_ARM64: - object->cpusubtype = CPU_SUBTYPE_ARM64_ALL; - break; - default: - object->cpusubtype = 0; - break; - } - } - - /* Validate that we support the target architecture and record its - * endianness. - */ - - switch(object->cputype) { - case CPU_TYPE_ARM: - case CPU_TYPE_ARM64: - case CPU_TYPE_I386: - case CPU_TYPE_X86_64: - object->target_order = NX_LittleEndian; - break; - default: - rval = KERN_NOT_SUPPORTED; - kxld_log(kKxldLogLinking, kKxldLogErr, - kKxldLogArchNotSupported, object->cputype); - goto finish; - } - - rval = KERN_SUCCESS; + /* User-space must look up the architecture it's running on and the target + * architecture at run-time. + */ + + kern_return_t rval = KERN_FAILURE; + const NXArchInfo *host_arch = NULL; + + check(object); + + host_arch = NXGetLocalArchInfo(); + require_action(host_arch, finish, rval = KERN_FAILURE); + + object->host_order = host_arch->byteorder; + + /* If the user did not specify a cputype, use the local architecture. + */ + + if (cputype) { + object->cputype = cputype; + object->cpusubtype = cpusubtype; + } else { + object->cputype = host_arch->cputype; + object->target_order = object->host_order; + + switch (object->cputype) { + case CPU_TYPE_I386: + object->cpusubtype = CPU_SUBTYPE_I386_ALL; + break; + case CPU_TYPE_X86_64: + object->cpusubtype = CPU_SUBTYPE_X86_64_ALL; + break; + case CPU_TYPE_ARM: + object->cpusubtype = CPU_SUBTYPE_ARM_ALL; + break; + case CPU_TYPE_ARM64: + object->cpusubtype = CPU_SUBTYPE_ARM64_ALL; + break; + default: + object->cpusubtype = 0; + break; + } + } + + /* Validate that we support the target architecture and record its + * endianness. + */ + + switch (object->cputype) { + case CPU_TYPE_ARM: + case CPU_TYPE_ARM64: + case CPU_TYPE_I386: + case CPU_TYPE_X86_64: + object->target_order = NX_LittleEndian; + break; + default: + rval = KERN_NOT_SUPPORTED; + kxld_log(kKxldLogLinking, kKxldLogErr, + kKxldLogArchNotSupported, object->cputype); + goto finish; + } + + rval = KERN_SUCCESS; finish: - return rval; + return rval; #endif /* KERNEL */ } @@ -466,94 +473,95 @@ finish: static kern_return_t get_macho_slice_for_arch(KXLDObject *object, u_char *file, u_long size) { - kern_return_t rval = KERN_FAILURE; - struct mach_header *mach_hdr = NULL; + kern_return_t rval = KERN_FAILURE; + struct mach_header *mach_hdr = NULL; #if !KERNEL - struct fat_header *fat = (struct fat_header *) ((void *) file); - struct fat_arch *archs = (struct fat_arch *) &fat[1]; - boolean_t swap = FALSE; + struct fat_header *fat = (struct fat_header *) ((void *) file); + struct fat_arch *archs = (struct fat_arch *) &fat[1]; + boolean_t swap = FALSE; #endif /* KERNEL */ - u_char *my_file = file; - u_long my_file_size = size; - - check(object); - check(file); - check(size); + u_char *my_file = file; + u_long my_file_size = size; + + check(object); + check(file); + check(size); - /* We are assuming that we will never receive a fat file in the kernel */ + /* We are assuming that we will never receive a fat file in the kernel */ #if !KERNEL - require_action(size >= sizeof(*fat), finish, - rval=KERN_FAILURE; - kxld_log(kKxldLogLinking, kKxldLogErr, kKxldLogTruncatedMachO)); - - /* The fat header is always big endian, so swap if necessary */ - if (fat->magic == FAT_CIGAM) { - (void) swap_fat_header(fat, object->host_order); - swap = TRUE; - } - - if (fat->magic == FAT_MAGIC) { - struct fat_arch *arch = NULL; - - require_action(size >= (sizeof(*fat) + (fat->nfat_arch * sizeof(*archs))), - finish, - rval=KERN_FAILURE; - kxld_log(kKxldLogLinking, kKxldLogErr, kKxldLogTruncatedMachO)); - - /* Swap the fat_arch structures if necessary */ - if (swap) { - (void) swap_fat_arch(archs, fat->nfat_arch, object->host_order); - } - - /* Locate the Mach-O for the requested architecture */ - - arch = NXFindBestFatArch(object->cputype, object->cpusubtype, archs, fat->nfat_arch); - require_action(arch, finish, rval=KERN_FAILURE; - kxld_log(kKxldLogLinking, kKxldLogErr, kKxldLogArchNotFound)); - require_action(size >= arch->offset + arch->size, finish, - rval=KERN_FAILURE; - kxld_log(kKxldLogLinking, kKxldLogErr, kKxldLogTruncatedMachO)); - - my_file = my_file + arch->offset; - my_file_size = arch->size; - } + require_action(size >= sizeof(*fat), finish, + rval = KERN_FAILURE; + kxld_log(kKxldLogLinking, kKxldLogErr, kKxldLogTruncatedMachO)); + + /* The fat header is always big endian, so swap if necessary */ + if (fat->magic == FAT_CIGAM) { + (void) swap_fat_header(fat, object->host_order); + swap = TRUE; + } + + if (fat->magic == FAT_MAGIC) { + struct fat_arch *arch = NULL; + u_long arch_size; + boolean_t ovr = os_mul_and_add_overflow(fat->nfat_arch, sizeof(*archs), sizeof(*fat), &arch_size); + + require_action(!ovr && size >= arch_size, + finish, + rval = KERN_FAILURE; + kxld_log(kKxldLogLinking, kKxldLogErr, kKxldLogTruncatedMachO)); + + /* Swap the fat_arch structures if necessary */ + if (swap) { + (void) swap_fat_arch(archs, fat->nfat_arch, object->host_order); + } + + /* Locate the Mach-O for the requested architecture */ + + arch = NXFindBestFatArch(object->cputype, object->cpusubtype, archs, fat->nfat_arch); + require_action(arch, finish, rval = KERN_FAILURE; + kxld_log(kKxldLogLinking, kKxldLogErr, kKxldLogArchNotFound)); + require_action(size >= arch->offset + arch->size, finish, + rval = KERN_FAILURE; + kxld_log(kKxldLogLinking, kKxldLogErr, kKxldLogTruncatedMachO)); + + my_file = my_file + arch->offset; + my_file_size = arch->size; + } #endif /* !KERNEL */ - /* Swap the Mach-O's headers to this architecture if necessary */ - if (kxld_object_is_32_bit(object)) { - rval = validate_and_swap_macho_32(my_file, my_file_size + /* Swap the Mach-O's headers to this architecture if necessary */ + if (kxld_object_is_32_bit(object)) { + rval = validate_and_swap_macho_32(my_file, my_file_size #if !KERNEL - , object->host_order + , object->host_order #endif /* !KERNEL */ - ); - } else { - rval = validate_and_swap_macho_64(my_file, my_file_size + ); + } else { + rval = validate_and_swap_macho_64(my_file, my_file_size #if !KERNEL - , object->host_order + , object->host_order #endif /* !KERNEL */ - ); - } - require_noerr(rval, finish); - - mach_hdr = (struct mach_header *) ((void *) my_file); - require_action(object->cputype == mach_hdr->cputype, finish, - rval=KERN_FAILURE; - kxld_log(kKxldLogLinking, kKxldLogErr, kKxldLogTruncatedMachO)); - object->cpusubtype = mach_hdr->cpusubtype; /* */ - - if (isOldInterface) { - object->file = my_file; - object->size = my_file_size; - } - else { - object->split_info.kextExecutable = my_file; - object->split_info.kextSize = my_file_size; - } - - rval = KERN_SUCCESS; + ); + } + require_noerr(rval, finish); + + mach_hdr = (struct mach_header *) ((void *) my_file); + require_action(object->cputype == mach_hdr->cputype, finish, + rval = KERN_FAILURE; + kxld_log(kKxldLogLinking, kKxldLogErr, kKxldLogTruncatedMachO)); + object->cpusubtype = mach_hdr->cpusubtype; /* */ + + if (isOldInterface) { + object->file = my_file; + object->size = my_file_size; + } else { + object->split_info.kextExecutable = my_file; + object->split_info.kextSize = my_file_size; + } + + rval = KERN_SUCCESS; finish: - return rval; + return rval; } /******************************************************************************* @@ -562,221 +570,239 @@ static kern_return_t init_from_final_linked_image(KXLDObject *object, u_int *filetype_out, struct symtab_command **symtab_hdr_out) { - kern_return_t rval = KERN_FAILURE; - KXLDSeg *seg = NULL; - KXLDSect *sect = NULL; - struct load_command *cmd_hdr = NULL; - struct symtab_command *symtab_hdr = NULL; - struct uuid_command *uuid_hdr = NULL; - struct version_min_command *versionmin_hdr = NULL; - struct source_version_command *source_version_hdr = NULL; - u_long base_offset = 0; - u_long offset = 0; - u_long sect_offset = 0; - u_int filetype = 0; - u_int i = 0; - u_int j = 0; - u_int segi = 0; - u_int secti = 0; - u_int nsegs = 0; - u_int nsects = 0; - u_int ncmds = 0; - u_char *my_file; - - if (isOldInterface) { - my_file = object->file; - } - else { - my_file = object->split_info.kextExecutable; - } - - KXLD_3264_FUNC(kxld_object_is_32_bit(object), base_offset, - get_macho_cmd_data_32, get_macho_cmd_data_64, - my_file, offset, &filetype, &ncmds); - - /* First pass to count segments and sections */ - - offset = base_offset; - for (i = 0; i < ncmds; ++i, offset += cmd_hdr->cmdsize) { - cmd_hdr = (struct load_command *) ((void *) (my_file + offset)); - - switch(cmd_hdr->cmd) { + kern_return_t rval = KERN_FAILURE; + KXLDSeg *seg = NULL; + KXLDSect *sect = NULL; + struct load_command *cmd_hdr = NULL; + struct symtab_command *symtab_hdr = NULL; + struct uuid_command *uuid_hdr = NULL; + struct version_min_command *versionmin_hdr = NULL; + struct build_version_command *build_version_hdr = NULL; + struct source_version_command *source_version_hdr = NULL; + u_long base_offset = 0; + u_long offset = 0; + u_long sect_offset = 0; + u_int filetype = 0; + u_int i = 0; + u_int j = 0; + u_int segi = 0; + u_int secti = 0; + u_int nsegs = 0; + u_int nsects = 0; + u_int ncmds = 0; + u_char *my_file; + + if (isOldInterface) { + my_file = object->file; + } else { + my_file = object->split_info.kextExecutable; + } + + KXLD_3264_FUNC(kxld_object_is_32_bit(object), base_offset, + get_macho_cmd_data_32, get_macho_cmd_data_64, + my_file, offset, &filetype, &ncmds); + + /* First pass to count segments and sections */ + + offset = base_offset; + for (i = 0; i < ncmds; ++i, offset += cmd_hdr->cmdsize) { + cmd_hdr = (struct load_command *) ((void *) (my_file + offset)); + + switch (cmd_hdr->cmd) { #if KXLD_USER_OR_ILP32 - case LC_SEGMENT: - { - struct segment_command *seg_hdr = - (struct segment_command *) cmd_hdr; - - /* Ignore segments with no vm size */ - if (!seg_hdr->vmsize) continue; - - ++nsegs; - nsects += seg_hdr->nsects; - } - break; + case LC_SEGMENT: + { + struct segment_command *seg_hdr = + (struct segment_command *) cmd_hdr; + + /* Ignore segments with no vm size */ + if (!seg_hdr->vmsize) { + continue; + } + + ++nsegs; + nsects += seg_hdr->nsects; + } + break; #endif /* KXLD_USER_OR_ILP32 */ #if KXLD_USER_OR_LP64 - case LC_SEGMENT_64: - { - struct segment_command_64 *seg_hdr = - (struct segment_command_64 *) ((void *) cmd_hdr); - - /* Ignore segments with no vm size */ - if (!seg_hdr->vmsize) continue; - - ++nsegs; - nsects += seg_hdr->nsects; - } - break; + case LC_SEGMENT_64: + { + struct segment_command_64 *seg_hdr = + (struct segment_command_64 *) ((void *) cmd_hdr); + + /* Ignore segments with no vm size */ + if (!seg_hdr->vmsize) { + continue; + } + + ++nsegs; + nsects += seg_hdr->nsects; + } + break; #endif /* KXLD_USER_OR_LP64 */ - default: - continue; - } - } + default: + continue; + } + } - /* Allocate the segments and sections */ + /* Allocate the segments and sections */ - if (nsegs) { - rval = kxld_array_init(&object->segs, sizeof(KXLDSeg), nsegs); - require_noerr(rval, finish); + if (nsegs) { + rval = kxld_array_init(&object->segs, sizeof(KXLDSeg), nsegs); + require_noerr(rval, finish); - rval = kxld_array_init(&object->sects, sizeof(KXLDSect), nsects); - require_noerr(rval, finish); - } + rval = kxld_array_init(&object->sects, sizeof(KXLDSect), nsects); + require_noerr(rval, finish); + } - /* Initialize the segments and sections */ + /* Initialize the segments and sections */ - offset = base_offset; - for (i = 0; i < ncmds; ++i, offset += cmd_hdr->cmdsize) { - cmd_hdr = (struct load_command *) ((void *) (my_file + offset)); - seg = NULL; + offset = base_offset; + for (i = 0; i < ncmds; ++i, offset += cmd_hdr->cmdsize) { + cmd_hdr = (struct load_command *) ((void *) (my_file + offset)); + seg = NULL; - switch(cmd_hdr->cmd) { + switch (cmd_hdr->cmd) { #if KXLD_USER_OR_ILP32 - case LC_SEGMENT: - { - struct segment_command *seg_hdr = - (struct segment_command *) cmd_hdr; + case LC_SEGMENT: + { + struct segment_command *seg_hdr = + (struct segment_command *) cmd_hdr; - /* Ignore segments with no vm size */ - if (!seg_hdr->vmsize) continue; + /* Ignore segments with no vm size */ + if (!seg_hdr->vmsize) { + continue; + } - seg = kxld_array_get_item(&object->segs, segi++); + seg = kxld_array_get_item(&object->segs, segi++); - rval = kxld_seg_init_from_macho_32(seg, seg_hdr); - require_noerr(rval, finish); + rval = kxld_seg_init_from_macho_32(seg, seg_hdr); + require_noerr(rval, finish); - sect_offset = offset + sizeof(*seg_hdr); - } - break; + sect_offset = offset + sizeof(*seg_hdr); + } + break; #endif /* KXLD_USER_OR_ILP32 */ #if KXLD_USER_OR_LP64 - case LC_SEGMENT_64: - { - struct segment_command_64 *seg_hdr = - (struct segment_command_64 *) ((void *) cmd_hdr); + case LC_SEGMENT_64: + { + struct segment_command_64 *seg_hdr = + (struct segment_command_64 *) ((void *) cmd_hdr); - /* Ignore segments with no vm size */ - if (!seg_hdr->vmsize) continue; + /* Ignore segments with no vm size */ + if (!seg_hdr->vmsize) { + continue; + } - seg = kxld_array_get_item(&object->segs, segi++); + seg = kxld_array_get_item(&object->segs, segi++); - rval = kxld_seg_init_from_macho_64(seg, seg_hdr); - require_noerr(rval, finish); + rval = kxld_seg_init_from_macho_64(seg, seg_hdr); + require_noerr(rval, finish); - sect_offset = offset + sizeof(*seg_hdr); - } - break; + sect_offset = offset + sizeof(*seg_hdr); + } + break; #endif /* KXLD_USER_OR_LP64 */ - case LC_SYMTAB: - symtab_hdr = (struct symtab_command *) cmd_hdr; - break; - case LC_UUID: - uuid_hdr = (struct uuid_command *) cmd_hdr; - kxld_uuid_init_from_macho(&object->uuid, uuid_hdr); - break; - case LC_VERSION_MIN_MACOSX: - case LC_VERSION_MIN_IPHONEOS: - case LC_VERSION_MIN_TVOS: - case LC_VERSION_MIN_WATCHOS: - versionmin_hdr = (struct version_min_command *) cmd_hdr; - kxld_versionmin_init_from_macho(&object->versionmin, versionmin_hdr); - break; - case LC_SOURCE_VERSION: - source_version_hdr = (struct source_version_command *) (void *) cmd_hdr; - kxld_srcversion_init_from_macho(&object->srcversion, source_version_hdr); - break; - case LC_DYSYMTAB: - object->dysymtab_hdr = (struct dysymtab_command *) cmd_hdr; - rval = kxld_reloc_create_macho(&object->extrelocs, &object->relocator, - (struct relocation_info *) ((void *) (my_file + object->dysymtab_hdr->extreloff)), - object->dysymtab_hdr->nextrel); - require_noerr(rval, finish); - - rval = kxld_reloc_create_macho(&object->locrelocs, &object->relocator, - (struct relocation_info *) ((void *) (my_file + object->dysymtab_hdr->locreloff)), - object->dysymtab_hdr->nlocrel); - require_noerr(rval, finish); - - break; - case LC_UNIXTHREAD: - case LC_MAIN: - /* Don't need to do anything with UNIXTHREAD or MAIN for the kernel */ - require_action(kxld_object_is_kernel(object), - finish, rval=KERN_FAILURE; - kxld_log(kKxldLogLinking, kKxldLogErr, kKxldLogMalformedMachO - "LC_UNIXTHREAD/LC_MAIN segment is not valid in a kext.")); - break; - case LC_SEGMENT_SPLIT_INFO: - if (isSplitKext) { - struct linkedit_data_command *split_info_hdr = NULL; - split_info_hdr = (struct linkedit_data_command *) (void *) cmd_hdr; - kxld_splitinfolc_init_from_macho(&object->splitinfolc, split_info_hdr); - } - break; - case LC_CODE_SIGNATURE: - case LC_DYLD_INFO: - case LC_DYLD_INFO_ONLY: - case LC_FUNCTION_STARTS: - case LC_DATA_IN_CODE: - case LC_DYLIB_CODE_SIGN_DRS: - /* Various metadata that might be stored in the linkedit segment */ - break; - default: - rval=KERN_FAILURE; - kxld_log(kKxldLogLinking, kKxldLogErr, kKxldLogMalformedMachO - "Invalid load command type in MH_KEXT_BUNDLE kext: %u.", cmd_hdr->cmd); - goto finish; - } - - if (seg) { - - /* Initialize the sections */ - for (j = 0; j < seg->sects.nitems; ++j, ++secti) { - sect = kxld_array_get_item(&object->sects, secti); - - KXLD_3264_FUNC(kxld_object_is_32_bit(object), rval, - kxld_sect_init_from_macho_32, kxld_sect_init_from_macho_64, - sect, my_file, §_offset, secti, &object->relocator); - require_noerr(rval, finish); - - /* Add the section to the segment. This will also make sure - * that the sections and segments have the same segname. - */ - rval = kxld_seg_add_section(seg, sect); - require_noerr(rval, finish); - } - rval = kxld_seg_finish_init(seg); - require_noerr(rval, finish); - } - } - - if (filetype_out) *filetype_out = filetype; - if (symtab_hdr_out) *symtab_hdr_out = symtab_hdr; - object->is_final_image = TRUE; - rval = KERN_SUCCESS; + case LC_SYMTAB: + symtab_hdr = (struct symtab_command *) cmd_hdr; + break; + case LC_UUID: + uuid_hdr = (struct uuid_command *) cmd_hdr; + kxld_uuid_init_from_macho(&object->uuid, uuid_hdr); + break; + case LC_VERSION_MIN_MACOSX: + case LC_VERSION_MIN_IPHONEOS: + case LC_VERSION_MIN_TVOS: + case LC_VERSION_MIN_WATCHOS: + versionmin_hdr = (struct version_min_command *) cmd_hdr; + kxld_versionmin_init_from_macho(&object->versionmin, versionmin_hdr); + break; + case LC_BUILD_VERSION: + build_version_hdr = (struct build_version_command *)cmd_hdr; + kxld_versionmin_init_from_build_cmd(&object->versionmin, build_version_hdr); + break; + case LC_SOURCE_VERSION: + source_version_hdr = (struct source_version_command *) (void *) cmd_hdr; + kxld_srcversion_init_from_macho(&object->srcversion, source_version_hdr); + break; + case LC_DYSYMTAB: + object->dysymtab_hdr = (struct dysymtab_command *) cmd_hdr; + rval = kxld_reloc_create_macho(&object->extrelocs, &object->relocator, + (struct relocation_info *) ((void *) (my_file + object->dysymtab_hdr->extreloff)), + object->dysymtab_hdr->nextrel); + require_noerr(rval, finish); + + rval = kxld_reloc_create_macho(&object->locrelocs, &object->relocator, + (struct relocation_info *) ((void *) (my_file + object->dysymtab_hdr->locreloff)), + object->dysymtab_hdr->nlocrel); + require_noerr(rval, finish); + + break; + case LC_UNIXTHREAD: + case LC_MAIN: + /* Don't need to do anything with UNIXTHREAD or MAIN for the kernel */ + require_action(kxld_object_is_kernel(object), + finish, rval = KERN_FAILURE; + kxld_log(kKxldLogLinking, kKxldLogErr, kKxldLogMalformedMachO + "LC_UNIXTHREAD/LC_MAIN segment is not valid in a kext.")); + break; + case LC_SEGMENT_SPLIT_INFO: + if (isSplitKext) { + struct linkedit_data_command *split_info_hdr = NULL; + split_info_hdr = (struct linkedit_data_command *) (void *) cmd_hdr; + kxld_splitinfolc_init_from_macho(&object->splitinfolc, split_info_hdr); + } + break; + case LC_NOTE: + /* binary blob of data */ + break; + case LC_CODE_SIGNATURE: + case LC_DYLD_INFO: + case LC_DYLD_INFO_ONLY: + case LC_FUNCTION_STARTS: + case LC_DATA_IN_CODE: + case LC_DYLIB_CODE_SIGN_DRS: + /* Various metadata that might be stored in the linkedit segment */ + break; + default: + rval = KERN_FAILURE; + kxld_log(kKxldLogLinking, kKxldLogErr, kKxldLogMalformedMachO + "Invalid load command type in MH_KEXT_BUNDLE kext: %u.", cmd_hdr->cmd); + goto finish; + } + + if (seg) { + /* Initialize the sections */ + for (j = 0; j < seg->sects.nitems; ++j, ++secti) { + sect = kxld_array_get_item(&object->sects, secti); + + KXLD_3264_FUNC(kxld_object_is_32_bit(object), rval, + kxld_sect_init_from_macho_32, kxld_sect_init_from_macho_64, + sect, my_file, §_offset, secti, &object->relocator); + require_noerr(rval, finish); + + /* Add the section to the segment. This will also make sure + * that the sections and segments have the same segname. + */ + rval = kxld_seg_add_section(seg, sect); + require_noerr(rval, finish); + } + rval = kxld_seg_finish_init(seg); + require_noerr(rval, finish); + } + } + + if (filetype_out) { + *filetype_out = filetype; + } + if (symtab_hdr_out) { + *symtab_hdr_out = symtab_hdr; + } + object->is_final_image = TRUE; + rval = KERN_SUCCESS; finish: - return rval; + return rval; } /******************************************************************************* @@ -784,81 +810,79 @@ finish: static kern_return_t init_from_execute(KXLDObject *object) { - kern_return_t rval = KERN_FAILURE; - struct symtab_command *symtab_hdr = NULL; - u_int filetype = 0; - KXLDSeg * kernel_linkedit_seg = NULL; // used if running kernel + kern_return_t rval = KERN_FAILURE; + struct symtab_command *symtab_hdr = NULL; + u_int filetype = 0; + KXLDSeg * kernel_linkedit_seg = NULL; // used if running kernel #if KXLD_USER_OR_OBJECT - KXLDSeg *seg = NULL; - KXLDSect *sect = NULL; - KXLDSectionName *sname = NULL; - u_int i = 0, j = 0, k = 0; + KXLDSeg *seg = NULL; + KXLDSect *sect = NULL; + KXLDSectionName *sname = NULL; + u_int i = 0, j = 0, k = 0; #endif /* KXLD_USER_OR_OBJECT */ - u_char *my_file; - - check(object); - - if (isOldInterface) { - my_file = object->file; - } - else { - my_file = object->split_info.kextExecutable; - } - - require_action(kxld_object_is_kernel(object), finish, rval=KERN_FAILURE); - - rval = init_from_final_linked_image(object, &filetype, &symtab_hdr); - require_noerr(rval, finish); - - require_action(filetype == MH_EXECUTE, finish, rval=KERN_FAILURE; - kxld_log(kKxldLogLinking, kKxldLogErr, kKxldLogMalformedMachO - "The kernel file is not of type MH_EXECUTE.")); - - /* Initialize the symbol table. If this is the running kernel - * we will work from the in-memory linkedit segment; - * otherwise we work from the whole mach-o image. - */ + u_char *my_file; + + check(object); + + if (isOldInterface) { + my_file = object->file; + } else { + my_file = object->split_info.kextExecutable; + } + + require_action(kxld_object_is_kernel(object), finish, rval = KERN_FAILURE); + + rval = init_from_final_linked_image(object, &filetype, &symtab_hdr); + require_noerr(rval, finish); + + require_action(filetype == MH_EXECUTE, finish, rval = KERN_FAILURE; + kxld_log(kKxldLogLinking, kKxldLogErr, kKxldLogMalformedMachO + "The kernel file is not of type MH_EXECUTE.")); + + /* Initialize the symbol table. If this is the running kernel + * we will work from the in-memory linkedit segment; + * otherwise we work from the whole mach-o image. + */ #if KERNEL - kernel_linkedit_seg = kxld_object_get_seg_by_name(object, SEG_LINKEDIT); - require_action(kernel_linkedit_seg, finish, rval=KERN_FAILURE; - kxld_log(kKxldLogLinking, kKxldLogErr, kKxldLogMalformedMachO)); + kernel_linkedit_seg = kxld_object_get_seg_by_name(object, SEG_LINKEDIT); + require_action(kernel_linkedit_seg, finish, rval = KERN_FAILURE; + kxld_log(kKxldLogLinking, kKxldLogErr, kKxldLogMalformedMachO)); #endif - KXLD_3264_FUNC(kxld_object_is_32_bit(object), rval, - kxld_symtab_init_from_macho_32, kxld_symtab_init_from_macho_64, - object->symtab, symtab_hdr, my_file, kernel_linkedit_seg); - require_noerr(rval, finish); + KXLD_3264_FUNC(kxld_object_is_32_bit(object), rval, + kxld_symtab_init_from_macho_32, kxld_symtab_init_from_macho_64, + object->symtab, symtab_hdr, my_file, kernel_linkedit_seg); + require_noerr(rval, finish); #if KXLD_USER_OR_OBJECT - /* Save off the order of section names so that we can lay out kext - * sections for MH_OBJECT-based systems. - */ - if (target_supports_object(object)) { - - rval = kxld_array_init(object->section_order, sizeof(KXLDSectionName), - object->sects.nitems); - require_noerr(rval, finish); - - /* Copy the section names into the section_order array for future kext - * section ordering. - */ - for (i = 0, k = 0; i < object->segs.nitems; ++i) { - seg = kxld_array_get_item(&object->segs, i); - - for (j = 0; j < seg->sects.nitems; ++j, ++k) { - sect = *(KXLDSect **) kxld_array_get_item(&seg->sects, j); - sname = kxld_array_get_item(object->section_order, k); - - strlcpy(sname->segname, sect->segname, sizeof(sname->segname)); - strlcpy(sname->sectname, sect->sectname, sizeof(sname->sectname)); - } - } - } + /* Save off the order of section names so that we can lay out kext + * sections for MH_OBJECT-based systems. + */ + if (target_supports_object(object)) { + rval = kxld_array_init(object->section_order, sizeof(KXLDSectionName), + object->sects.nitems); + require_noerr(rval, finish); + + /* Copy the section names into the section_order array for future kext + * section ordering. + */ + for (i = 0, k = 0; i < object->segs.nitems; ++i) { + seg = kxld_array_get_item(&object->segs, i); + + for (j = 0; j < seg->sects.nitems; ++j, ++k) { + sect = *(KXLDSect **) kxld_array_get_item(&seg->sects, j); + sname = kxld_array_get_item(object->section_order, k); + + strlcpy(sname->segname, sect->segname, sizeof(sname->segname)); + strlcpy(sname->sectname, sect->sectname, sizeof(sname->sectname)); + } + } + } #endif /* KXLD_USER_OR_OBJECT */ - rval = KERN_SUCCESS; + rval = KERN_SUCCESS; finish: - return rval; + return rval; } #if KXLD_USER_OR_BUNDLE @@ -867,251 +891,260 @@ finish: static boolean_t target_supports_bundle(const KXLDObject *object __unused) { - return TRUE; + return TRUE; } /******************************************************************************* *******************************************************************************/ -static kern_return_t +static kern_return_t init_from_bundle(KXLDObject *object) { - kern_return_t rval = KERN_FAILURE; - struct symtab_command *symtab_hdr = NULL; - u_int filetype = 0; - u_char *my_file; - - check(object); - - if (isOldInterface) { - my_file = object->file; - } - else { - my_file = object->split_info.kextExecutable; - } - - require_action(target_supports_bundle(object), finish, - rval=KERN_FAILURE; - kxld_log(kKxldLogLinking, kKxldLogErr, - kKxldLogFiletypeNotSupported, MH_KEXT_BUNDLE)); - - rval = init_from_final_linked_image(object, &filetype, &symtab_hdr); - require_noerr(rval, finish); - - require_action(filetype == MH_KEXT_BUNDLE, finish, - rval=KERN_FAILURE); - - KXLD_3264_FUNC(kxld_object_is_32_bit(object), rval, - kxld_symtab_init_from_macho_32, kxld_symtab_init_from_macho_64, - object->symtab, symtab_hdr, my_file, - /* kernel_linkedit_seg */ NULL); - require_noerr(rval, finish); - - rval = KERN_SUCCESS; + kern_return_t rval = KERN_FAILURE; + struct symtab_command *symtab_hdr = NULL; + u_int filetype = 0; + u_char *my_file; + + check(object); + + if (isOldInterface) { + my_file = object->file; + } else { + my_file = object->split_info.kextExecutable; + } + + require_action(target_supports_bundle(object), finish, + rval = KERN_FAILURE; + kxld_log(kKxldLogLinking, kKxldLogErr, + kKxldLogFiletypeNotSupported, MH_KEXT_BUNDLE)); + + rval = init_from_final_linked_image(object, &filetype, &symtab_hdr); + require_noerr(rval, finish); + + require_action(filetype == MH_KEXT_BUNDLE, finish, + rval = KERN_FAILURE); + + KXLD_3264_FUNC(kxld_object_is_32_bit(object), rval, + kxld_symtab_init_from_macho_32, kxld_symtab_init_from_macho_64, + object->symtab, symtab_hdr, my_file, + /* kernel_linkedit_seg */ NULL); + require_noerr(rval, finish); + + rval = KERN_SUCCESS; finish: - return rval; + return rval; } #endif /* KXLD_USER_OR_BUNDLE */ #if KXLD_USER_OR_OBJECT /******************************************************************************* *******************************************************************************/ -static boolean_t target_supports_object(const KXLDObject *object) +static boolean_t +target_supports_object(const KXLDObject *object) { - return (object->cputype == CPU_TYPE_I386); + return object->cputype == CPU_TYPE_I386; } /******************************************************************************* *******************************************************************************/ -static kern_return_t +static kern_return_t init_from_object(KXLDObject *object) { - kern_return_t rval = KERN_FAILURE; - struct load_command *cmd_hdr = NULL; - struct symtab_command *symtab_hdr = NULL; - struct uuid_command *uuid_hdr = NULL; - KXLDSect *sect = NULL; - u_long offset = 0; - u_long sect_offset = 0; - u_int filetype = 0; - u_int ncmds = 0; - u_int nsects = 0; - u_int i = 0; - boolean_t has_segment = FALSE; - u_char *my_file; - - check(object); - - if (isOldInterface) { - my_file = object->file; - } - else { - my_file = object->split_info.kextExecutable; - } - - require_action(target_supports_object(object), - finish, rval=KERN_FAILURE; - kxld_log(kKxldLogLinking, kKxldLogErr, - kKxldLogFiletypeNotSupported, MH_OBJECT)); - - KXLD_3264_FUNC(kxld_object_is_32_bit(object), offset, - get_macho_cmd_data_32, get_macho_cmd_data_64, - my_file, offset, &filetype, &ncmds); - - require_action(filetype == MH_OBJECT, finish, rval=KERN_FAILURE); - - /* MH_OBJECTs use one unnamed segment to contain all of the sections. We - * loop over all of the load commands to initialize the structures we - * expect. Then, we'll use the unnamed segment to get to all of the - * sections, and then use those sections to create the actual segments. - */ - - for (; i < ncmds; ++i, offset += cmd_hdr->cmdsize) { - cmd_hdr = (struct load_command *) ((void *) (my_file + offset)); - - switch(cmd_hdr->cmd) { + kern_return_t rval = KERN_FAILURE; + struct load_command *cmd_hdr = NULL; + struct symtab_command *symtab_hdr = NULL; + struct uuid_command *uuid_hdr = NULL; + KXLDSect *sect = NULL; + u_long offset = 0; + u_long sect_offset = 0; + u_int filetype = 0; + u_int ncmds = 0; + u_int nsects = 0; + u_int i = 0; + boolean_t has_segment = FALSE; + u_char *my_file; + + check(object); + + if (isOldInterface) { + my_file = object->file; + } else { + my_file = object->split_info.kextExecutable; + } + + require_action(target_supports_object(object), + finish, rval = KERN_FAILURE; + kxld_log(kKxldLogLinking, kKxldLogErr, + kKxldLogFiletypeNotSupported, MH_OBJECT)); + + KXLD_3264_FUNC(kxld_object_is_32_bit(object), offset, + get_macho_cmd_data_32, get_macho_cmd_data_64, + my_file, offset, &filetype, &ncmds); + + require_action(filetype == MH_OBJECT, finish, rval = KERN_FAILURE); + + /* MH_OBJECTs use one unnamed segment to contain all of the sections. We + * loop over all of the load commands to initialize the structures we + * expect. Then, we'll use the unnamed segment to get to all of the + * sections, and then use those sections to create the actual segments. + */ + + for (; i < ncmds; ++i, offset += cmd_hdr->cmdsize) { + cmd_hdr = (struct load_command *) ((void *) (my_file + offset)); + + switch (cmd_hdr->cmd) { #if KXLD_USER_OR_ILP32 - case LC_SEGMENT: - { - struct segment_command *seg_hdr = - (struct segment_command *) cmd_hdr; - - /* Ignore segments with no vm size */ - if (!seg_hdr->vmsize) continue; - - /* Ignore LINKEDIT segments */ - if (streq_safe(seg_hdr->segname, SEG_LINKEDIT, - const_strlen(SEG_LINKEDIT))) - { - continue; - } - - require_action(kxld_object_is_32_bit(object), finish, rval=KERN_FAILURE; - kxld_log(kKxldLogLinking, kKxldLogErr, kKxldLogMalformedMachO - "LC_SEGMENT in 64-bit kext.")); - require_action(!has_segment, finish, rval=KERN_FAILURE; - kxld_log(kKxldLogLinking, kKxldLogErr, kKxldLogMalformedMachO - "Multiple segments in an MH_OBJECT kext.")); - - nsects = seg_hdr->nsects; - sect_offset = offset + sizeof(*seg_hdr); - has_segment = TRUE; - } - break; + case LC_SEGMENT: + { + struct segment_command *seg_hdr = + (struct segment_command *) cmd_hdr; + + /* Ignore segments with no vm size */ + if (!seg_hdr->vmsize) { + continue; + } + + /* Ignore LINKEDIT segments */ + if (streq_safe(seg_hdr->segname, SEG_LINKEDIT, + const_strlen(SEG_LINKEDIT))) { + continue; + } + + require_action(kxld_object_is_32_bit(object), finish, rval = KERN_FAILURE; + kxld_log(kKxldLogLinking, kKxldLogErr, kKxldLogMalformedMachO + "LC_SEGMENT in 64-bit kext.")); + require_action(!has_segment, finish, rval = KERN_FAILURE; + kxld_log(kKxldLogLinking, kKxldLogErr, kKxldLogMalformedMachO + "Multiple segments in an MH_OBJECT kext.")); + + nsects = seg_hdr->nsects; + sect_offset = offset + sizeof(*seg_hdr); + has_segment = TRUE; + } + break; #endif /* KXLD_USER_OR_ILP32 */ #if KXLD_USER_OR_LP64 - case LC_SEGMENT_64: - { - struct segment_command_64 *seg_hdr = - (struct segment_command_64 *) ((void *) cmd_hdr); - - /* Ignore segments with no vm size */ - if (!seg_hdr->vmsize) continue; - - /* Ignore LINKEDIT segments */ - if (streq_safe(seg_hdr->segname, SEG_LINKEDIT, - const_strlen(SEG_LINKEDIT))) - { - continue; - } - - require_action(!kxld_object_is_32_bit(object), finish, rval=KERN_FAILURE; - kxld_log(kKxldLogLinking, kKxldLogErr, kKxldLogMalformedMachO - "LC_SEGMENT_64 in a 32-bit kext.")); - require_action(!has_segment, finish, rval=KERN_FAILURE; - kxld_log(kKxldLogLinking, kKxldLogErr, kKxldLogMalformedMachO - "Multiple segments in an MH_OBJECT kext.")); - - nsects = seg_hdr->nsects; - sect_offset = offset + sizeof(*seg_hdr); - has_segment = TRUE; - } - break; + case LC_SEGMENT_64: + { + struct segment_command_64 *seg_hdr = + (struct segment_command_64 *) ((void *) cmd_hdr); + + /* Ignore segments with no vm size */ + if (!seg_hdr->vmsize) { + continue; + } + + /* Ignore LINKEDIT segments */ + if (streq_safe(seg_hdr->segname, SEG_LINKEDIT, + const_strlen(SEG_LINKEDIT))) { + continue; + } + + require_action(!kxld_object_is_32_bit(object), finish, rval = KERN_FAILURE; + kxld_log(kKxldLogLinking, kKxldLogErr, kKxldLogMalformedMachO + "LC_SEGMENT_64 in a 32-bit kext.")); + require_action(!has_segment, finish, rval = KERN_FAILURE; + kxld_log(kKxldLogLinking, kKxldLogErr, kKxldLogMalformedMachO + "Multiple segments in an MH_OBJECT kext.")); + + nsects = seg_hdr->nsects; + sect_offset = offset + sizeof(*seg_hdr); + has_segment = TRUE; + } + break; #endif /* KXLD_USER_OR_LP64 */ - case LC_SYMTAB: - symtab_hdr = (struct symtab_command *) cmd_hdr; - - KXLD_3264_FUNC(kxld_object_is_32_bit(object), rval, - kxld_symtab_init_from_macho_32, kxld_symtab_init_from_macho_64, - object->symtab, symtab_hdr, my_file, - /* kernel_linkedit_seg */ NULL); - require_noerr(rval, finish); - break; - case LC_UUID: - uuid_hdr = (struct uuid_command *) cmd_hdr; - kxld_uuid_init_from_macho(&object->uuid, uuid_hdr); - break; - case LC_UNIXTHREAD: - case LC_MAIN: - /* Don't need to do anything with UNIXTHREAD or MAIN */ - break; - case LC_CODE_SIGNATURE: - case LC_DYLD_INFO: - case LC_DYLD_INFO_ONLY: - case LC_FUNCTION_STARTS: - case LC_DATA_IN_CODE: - case LC_DYLIB_CODE_SIGN_DRS: - /* Various metadata that might be stored in the linkedit segment */ - break; - case LC_VERSION_MIN_MACOSX: - case LC_VERSION_MIN_IPHONEOS: - case LC_VERSION_MIN_TVOS: - case LC_VERSION_MIN_WATCHOS: - case LC_SOURCE_VERSION: - /* Not supported for object files, fall through */ - default: - rval = KERN_FAILURE; - kxld_log(kKxldLogLinking, kKxldLogErr, kKxldLogMalformedMachO - "Invalid load command type in MH_OBJECT kext: %u.", cmd_hdr->cmd); - goto finish; - } - } - - if (has_segment) { - - /* Get the number of sections from the segment and build the section index */ - - rval = kxld_array_init(&object->sects, sizeof(KXLDSect), nsects); - require_noerr(rval, finish); - - /* Loop over all of the sections to initialize the section index */ - - for (i = 0; i < nsects; ++i) { - sect = kxld_array_get_item(&object->sects, i); - - KXLD_3264_FUNC(kxld_object_is_32_bit(object), rval, - kxld_sect_init_from_macho_32, kxld_sect_init_from_macho_64, - sect, my_file, §_offset, i, &object->relocator); - require_noerr(rval, finish); - } - - /* Create special sections */ + case LC_SYMTAB: + symtab_hdr = (struct symtab_command *) cmd_hdr; + + KXLD_3264_FUNC(kxld_object_is_32_bit(object), rval, + kxld_symtab_init_from_macho_32, kxld_symtab_init_from_macho_64, + object->symtab, symtab_hdr, my_file, + /* kernel_linkedit_seg */ NULL); + require_noerr(rval, finish); + break; + case LC_UUID: + uuid_hdr = (struct uuid_command *) cmd_hdr; + kxld_uuid_init_from_macho(&object->uuid, uuid_hdr); + break; + case LC_UNIXTHREAD: + case LC_MAIN: + /* Don't need to do anything with UNIXTHREAD or MAIN */ + break; + case LC_CODE_SIGNATURE: + case LC_DYLD_INFO: + case LC_DYLD_INFO_ONLY: + case LC_FUNCTION_STARTS: + case LC_DATA_IN_CODE: + case LC_DYLIB_CODE_SIGN_DRS: + /* Various metadata that might be stored in the linkedit segment */ + break; + case LC_NOTE: + /* bag-of-bits carried with the binary: ignore */ + break; + case LC_BUILD_VERSION: + /* should be able to ignore build version commands */ + kxld_log(kKxldLogLinking, kKxldLogWarn, + "Ignoring LC_BUILD_VERSION (%u) in MH_OBJECT kext: (platform:%d)", + cmd_hdr->cmd, ((struct build_version_command *)cmd_hdr)->platform); + break; + case LC_VERSION_MIN_MACOSX: + case LC_VERSION_MIN_IPHONEOS: + case LC_VERSION_MIN_TVOS: + case LC_VERSION_MIN_WATCHOS: + case LC_SOURCE_VERSION: + /* Not supported for object files, fall through */ + default: + rval = KERN_FAILURE; + kxld_log(kKxldLogLinking, kKxldLogErr, kKxldLogMalformedMachO + "Invalid load command type in MH_OBJECT kext: %u.", cmd_hdr->cmd); + goto finish; + } + } + + if (has_segment) { + /* Get the number of sections from the segment and build the section index */ + + rval = kxld_array_init(&object->sects, sizeof(KXLDSect), nsects); + require_noerr(rval, finish); + + /* Loop over all of the sections to initialize the section index */ + + for (i = 0; i < nsects; ++i) { + sect = kxld_array_get_item(&object->sects, i); + + KXLD_3264_FUNC(kxld_object_is_32_bit(object), rval, + kxld_sect_init_from_macho_32, kxld_sect_init_from_macho_64, + sect, my_file, §_offset, i, &object->relocator); + require_noerr(rval, finish); + } + + /* Create special sections */ #if KXLD_USER_OR_GOT - rval = create_got(object); - require_noerr(rval, finish); + rval = create_got(object); + require_noerr(rval, finish); #endif /* KXLD_USER_OR_GOT */ #if KXLD_USER_OR_COMMON - rval = resolve_common_symbols(object); - require_noerr(rval, finish); + rval = resolve_common_symbols(object); + require_noerr(rval, finish); #endif /* KXLD_USER_OR_COMMON */ - /* Create the segments from the section index */ + /* Create the segments from the section index */ - rval = kxld_seg_create_seg_from_sections(&object->segs, &object->sects); - require_noerr(rval, finish); + rval = kxld_seg_create_seg_from_sections(&object->segs, &object->sects); + require_noerr(rval, finish); - rval = kxld_seg_finalize_object_segment(&object->segs, - object->section_order, get_macho_header_size(object)); - require_noerr(rval, finish); + rval = kxld_seg_finalize_object_segment(&object->segs, + object->section_order, get_macho_header_size(object)); + require_noerr(rval, finish); - rval = kxld_seg_init_linkedit(&object->segs); - require_noerr(rval, finish); - } + rval = kxld_seg_init_linkedit(&object->segs); + require_noerr(rval, finish); + } - rval = KERN_SUCCESS; + rval = KERN_SUCCESS; finish: - return rval; + return rval; } #endif /* KXLD_USER_OR_OBJECT */ @@ -1121,12 +1154,16 @@ finish: static u_long get_macho_cmd_data_32(u_char *file, u_long offset, u_int *filetype, u_int *ncmds) { - struct mach_header *mach_hdr = (struct mach_header *) ((void *) (file + offset)); + struct mach_header *mach_hdr = (struct mach_header *) ((void *) (file + offset)); - if (filetype) *filetype = mach_hdr->filetype; - if (ncmds) *ncmds = mach_hdr->ncmds; + if (filetype) { + *filetype = mach_hdr->filetype; + } + if (ncmds) { + *ncmds = mach_hdr->ncmds; + } - return sizeof(*mach_hdr); + return sizeof(*mach_hdr); } #endif /* KXLD_USER_OR_ILP32 */ @@ -1135,14 +1172,18 @@ get_macho_cmd_data_32(u_char *file, u_long offset, u_int *filetype, u_int *ncmds /******************************************************************************* *******************************************************************************/ static u_long -get_macho_cmd_data_64(u_char *file, u_long offset, u_int *filetype, u_int *ncmds) +get_macho_cmd_data_64(u_char *file, u_long offset, u_int *filetype, u_int *ncmds) { - struct mach_header_64 *mach_hdr = (struct mach_header_64 *) ((void *) (file + offset)); + struct mach_header_64 *mach_hdr = (struct mach_header_64 *) ((void *) (file + offset)); - if (filetype) *filetype = mach_hdr->filetype; - if (ncmds) *ncmds = mach_hdr->ncmds; + if (filetype) { + *filetype = mach_hdr->filetype; + } + if (ncmds) { + *ncmds = mach_hdr->ncmds; + } - return sizeof(*mach_hdr); + return sizeof(*mach_hdr); } #endif /* KXLD_USER_OR_LP64 */ @@ -1151,47 +1192,47 @@ get_macho_cmd_data_64(u_char *file, u_long offset, u_int *filetype, u_int *ncmd static u_long get_macho_header_size(const KXLDObject *object) { - KXLDSeg *seg = NULL; - u_long header_size = 0; - u_int i = 0; - boolean_t object_is_32_bit = kxld_object_is_32_bit(object); + KXLDSeg *seg = NULL; + u_long header_size = 0; + u_int i = 0; + boolean_t object_is_32_bit = kxld_object_is_32_bit(object); - check(object); + check(object); - /* Mach, segment, symtab, and UUID headers */ + /* Mach, segment, symtab, and UUID headers */ - header_size += object_is_32_bit ? sizeof(struct mach_header) : sizeof(struct mach_header_64); + header_size += object_is_32_bit ? sizeof(struct mach_header) : sizeof(struct mach_header_64); - for (i = 0; i < object->segs.nitems; ++i) { - seg = kxld_array_get_item(&object->segs, i); - header_size += kxld_seg_get_macho_header_size(seg, object_is_32_bit); - } + for (i = 0; i < object->segs.nitems; ++i) { + seg = kxld_array_get_item(&object->segs, i); + header_size += kxld_seg_get_macho_header_size(seg, object_is_32_bit); + } - header_size += kxld_symtab_get_macho_header_size(); + header_size += kxld_symtab_get_macho_header_size(); #if KXLD_PIC_KEXTS - if (target_supports_slideable_kexts(object)) { - header_size += kxld_reloc_get_macho_header_size(); - } -#endif /* KXLD_PIC_KEXTS */ + if (target_supports_slideable_kexts(object)) { + header_size += kxld_reloc_get_macho_header_size(); + } +#endif /* KXLD_PIC_KEXTS */ + + if (object->uuid.has_uuid) { + header_size += kxld_uuid_get_macho_header_size(); + } - if (object->uuid.has_uuid) { - header_size += kxld_uuid_get_macho_header_size(); - } + if (object->versionmin.has_versionmin) { + header_size += kxld_versionmin_get_macho_header_size(&object->versionmin); + } - if (object->versionmin.has_versionmin) { - header_size += kxld_versionmin_get_macho_header_size(); - } + if (object->srcversion.has_srcversion) { + header_size += kxld_srcversion_get_macho_header_size(); + } - if (object->srcversion.has_srcversion) { - header_size += kxld_srcversion_get_macho_header_size(); - } - - if (isSplitKext && object->splitinfolc.has_splitinfolc) { - header_size += kxld_splitinfolc_get_macho_header_size(); - } - - return header_size; + if (isSplitKext && object->splitinfolc.has_splitinfolc) { + header_size += kxld_splitinfolc_get_macho_header_size(); + } + + return header_size; } /******************************************************************************* @@ -1199,67 +1240,67 @@ get_macho_header_size(const KXLDObject *object) static u_long get_macho_data_size(const KXLDObject *object) { - KXLDSeg *seg = NULL; - u_long data_size = 0; - u_int i = 0; + KXLDSeg *seg = NULL; + u_long data_size = 0; + u_int i = 0; - check(object); + check(object); - /* total all segment vmsize values */ - for (i = 0; i < object->segs.nitems; ++i) { - seg = kxld_array_get_item(&object->segs, i); - data_size += (u_long) kxld_seg_get_vmsize(seg); - } + /* total all segment vmsize values */ + for (i = 0; i < object->segs.nitems; ++i) { + seg = kxld_array_get_item(&object->segs, i); + data_size += (u_long) kxld_seg_get_vmsize(seg); + } #if KXLD_PIC_KEXTS - { - /* ensure that when we eventually emit the final linked object, - * appending the __DYSYMTAB data after the __LINKEDIT data will - * not overflow the space allocated for the __LINKEDIT segment - */ - - u_long seg_vmsize = 0; - u_long symtab_size = 0; - u_long reloc_size = 0; - - /* get current __LINKEDIT sizes */ - seg = kxld_object_get_seg_by_name(object, SEG_LINKEDIT); - - seg_vmsize = (u_long) kxld_seg_get_vmsize(seg); - - /* get size of symbol table data that will eventually be dumped - * into the __LINKEDIT segment - */ - symtab_size = kxld_symtab_get_macho_data_size(object->symtab, kxld_object_is_32_bit(object)); - - if (target_supports_slideable_kexts(object)) { - /* get size of __DYSYMTAB relocation entries */ - reloc_size = kxld_reloc_get_macho_data_size(&object->locrelocs, &object->extrelocs); - } - - /* combine, and ensure they'll both fit within the page(s) - * allocated for the __LINKEDIT segment. If they'd overflow, - * increase the vmsize appropriately so no overflow will occur - */ - if ((symtab_size + reloc_size) > seg_vmsize) { - u_long overflow = (symtab_size + reloc_size) - seg_vmsize; - data_size += kxld_round_page_cross_safe(overflow); - } - } + { + /* ensure that when we eventually emit the final linked object, + * appending the __DYSYMTAB data after the __LINKEDIT data will + * not overflow the space allocated for the __LINKEDIT segment + */ + + u_long seg_vmsize = 0; + u_long symtab_size = 0; + u_long reloc_size = 0; + + /* get current __LINKEDIT sizes */ + seg = kxld_object_get_seg_by_name(object, SEG_LINKEDIT); + + seg_vmsize = (u_long) kxld_seg_get_vmsize(seg); + + /* get size of symbol table data that will eventually be dumped + * into the __LINKEDIT segment + */ + symtab_size = kxld_symtab_get_macho_data_size(object->symtab, kxld_object_is_32_bit(object)); + + if (target_supports_slideable_kexts(object)) { + /* get size of __DYSYMTAB relocation entries */ + reloc_size = kxld_reloc_get_macho_data_size(&object->locrelocs, &object->extrelocs); + } + + /* combine, and ensure they'll both fit within the page(s) + * allocated for the __LINKEDIT segment. If they'd overflow, + * increase the vmsize appropriately so no overflow will occur + */ + if ((symtab_size + reloc_size) > seg_vmsize) { + u_long overflow = (symtab_size + reloc_size) - seg_vmsize; + data_size += kxld_round_page_cross_safe(overflow); + } + } #endif // KXLD_PIC_KEXTS - return data_size; + return data_size; } /******************************************************************************* *******************************************************************************/ -boolean_t +boolean_t kxld_object_target_needs_swap(const KXLDObject *object __unused) { #if KERNEL - return FALSE; + return FALSE; #else - return (object->target_order != object->host_order); + return object->target_order != object->host_order; #endif /* KERNEL */ } @@ -1268,139 +1309,139 @@ kxld_object_target_needs_swap(const KXLDObject *object __unused) KXLDSeg * kxld_object_get_seg_by_name(const KXLDObject *object, const char *segname) { - KXLDSeg *seg = NULL; - u_int i = 0; + KXLDSeg *seg = NULL; + u_int i = 0; - for (i = 0; i < object->segs.nitems; ++i) { - seg = kxld_array_get_item(&object->segs, i); + for (i = 0; i < object->segs.nitems; ++i) { + seg = kxld_array_get_item(&object->segs, i); - if (streq_safe(segname, seg->segname, sizeof(seg->segname))) break; + if (streq_safe(segname, seg->segname, sizeof(seg->segname))) { + break; + } - seg = NULL; - } + seg = NULL; + } - return seg; + return seg; } /******************************************************************************* *******************************************************************************/ -const KXLDRelocator * +const KXLDRelocator * kxld_object_get_relocator(const KXLDObject * object) { - check(object); + check(object); - return &object->relocator; + return &object->relocator; } /******************************************************************************* *******************************************************************************/ KXLDSect * -kxld_object_get_sect_by_name(const KXLDObject *object, const char *segname, +kxld_object_get_sect_by_name(const KXLDObject *object, const char *segname, const char *sectname) { - KXLDSect *sect = NULL; - u_int i = 0; + KXLDSect *sect = NULL; + u_int i = 0; - for (i = 0; i < object->sects.nitems; ++i) { - sect = kxld_array_get_item(&object->sects, i); + for (i = 0; i < object->sects.nitems; ++i) { + sect = kxld_array_get_item(&object->sects, i); - if (streq_safe(segname, sect->segname, sizeof(sect->segname)) && - streq_safe(sectname, sect->sectname, sizeof(sect->sectname))) - { - break; - } + if (streq_safe(segname, sect->segname, sizeof(sect->segname)) && + streq_safe(sectname, sect->sectname, sizeof(sect->sectname))) { + break; + } - sect = NULL; - } + sect = NULL; + } - return sect; + return sect; } /******************************************************************************* *******************************************************************************/ -const KXLDReloc * +const KXLDReloc * kxld_object_get_reloc_at_symbol(const KXLDObject *object, const KXLDSym *sym) { - const KXLDReloc *reloc = NULL; - const KXLDSect *sect = NULL; - uint32_t offset = 0; + const KXLDReloc *reloc = NULL; + const KXLDSect *sect = NULL; + uint32_t offset = 0; - check(object); - check(sym); + check(object); + check(sym); - sect = kxld_object_get_section_by_index(object, sym->sectnum); - require(sect, finish); + sect = kxld_object_get_section_by_index(object, sym->sectnum); + require(sect, finish); - if (kxld_object_is_final_image(object)) { - reloc = kxld_reloc_get_reloc_by_offset(&object->extrelocs, - sym->base_addr); - if (!reloc) { - reloc = kxld_reloc_get_reloc_by_offset(&object->locrelocs, - sym->base_addr); - } - } else { - offset = kxld_sym_get_section_offset(sym, sect); - reloc = kxld_reloc_get_reloc_by_offset(§->relocs, offset); - } + if (kxld_object_is_final_image(object)) { + reloc = kxld_reloc_get_reloc_by_offset(&object->extrelocs, + sym->base_addr); + if (!reloc) { + reloc = kxld_reloc_get_reloc_by_offset(&object->locrelocs, + sym->base_addr); + } + } else { + offset = kxld_sym_get_section_offset(sym, sect); + reloc = kxld_reloc_get_reloc_by_offset(§->relocs, offset); + } finish: - return reloc; + return reloc; } /******************************************************************************* *******************************************************************************/ -const KXLDSym * -kxld_object_get_symbol_of_reloc(const KXLDObject *object, +const KXLDSym * +kxld_object_get_symbol_of_reloc(const KXLDObject *object, const KXLDReloc *reloc, const KXLDSect *sect) { - const KXLDSym *sym = NULL; - u_char *my_file; - - if (isOldInterface) { - my_file = object->file; - } - else { - my_file = object->split_info.kextExecutable; - } - - if (kxld_object_is_final_image(object)) { - sym = kxld_reloc_get_symbol(&object->relocator, reloc, my_file); - } else { - sym = kxld_reloc_get_symbol(&object->relocator, reloc, sect->data); - } - return sym; + const KXLDSym *sym = NULL; + u_char *my_file; + + if (isOldInterface) { + my_file = object->file; + } else { + my_file = object->split_info.kextExecutable; + } + + if (kxld_object_is_final_image(object)) { + sym = kxld_reloc_get_symbol(&object->relocator, reloc, my_file); + } else { + sym = kxld_reloc_get_symbol(&object->relocator, reloc, sect->data); + } + return sym; } /******************************************************************************* *******************************************************************************/ -const KXLDSect * +const KXLDSect * kxld_object_get_section_by_index(const KXLDObject *object, u_int sectnum) { - KXLDSect *sect = NULL; - - check(object); + KXLDSect *sect = NULL; - if (sectnum < object->sects.nitems) { - sect = kxld_array_get_item(&object->sects, sectnum); - } + check(object); - return sect; + if (sectnum < object->sects.nitems) { + sect = kxld_array_get_item(&object->sects, sectnum); + } + + return sect; } /******************************************************************************* *******************************************************************************/ -const KXLDArray * +const KXLDArray * kxld_object_get_extrelocs(const KXLDObject *object) { - const KXLDArray *rval = NULL; - - check(object); + const KXLDArray *rval = NULL; + + check(object); - if (kxld_object_is_final_image(object)) { - rval = &object->extrelocs; - } + if (kxld_object_is_final_image(object)) { + rval = &object->extrelocs; + } - return rval; + return rval; } /******************************************************************************* @@ -1408,9 +1449,9 @@ kxld_object_get_extrelocs(const KXLDObject *object) const KXLDSymtab * kxld_object_get_symtab(const KXLDObject *object) { - check(object); + check(object); - return object->symtab; + return object->symtab; } #if KXLD_USER_OR_GOT || KXLD_USER_OR_COMMON @@ -1419,18 +1460,18 @@ kxld_object_get_symtab(const KXLDObject *object) static kern_return_t add_section(KXLDObject *object, KXLDSect **sect) { - kern_return_t rval = KERN_FAILURE; - u_int nsects = object->sects.nitems; + kern_return_t rval = KERN_FAILURE; + u_int nsects = object->sects.nitems; - rval = kxld_array_resize(&object->sects, nsects + 1); - require_noerr(rval, finish); + rval = kxld_array_resize(&object->sects, nsects + 1); + require_noerr(rval, finish); - *sect = kxld_array_get_item(&object->sects, nsects); + *sect = kxld_array_get_item(&object->sects, nsects); - rval = KERN_SUCCESS; + rval = KERN_SUCCESS; finish: - return rval; + return rval; } #endif /* KXLD_USER_OR_GOT || KXLD_USER_OR_COMMON */ @@ -1443,72 +1484,74 @@ finish: static kern_return_t resolve_common_symbols(KXLDObject *object) { - kern_return_t rval = KERN_FAILURE; - KXLDSymtabIterator iter; - KXLDSym *sym = NULL; - KXLDSect *sect = NULL; - kxld_addr_t base_addr = 0; - kxld_size_t size = 0; - kxld_size_t total_size = 0; - u_int align = 0; - u_int max_align = 0; - u_int sectnum = 0; - - if (!kxld_object_target_supports_common_symbols(object)) { - rval = KERN_SUCCESS; - goto finish; - } - - /* Iterate over the common symbols to calculate their total aligned size */ - kxld_symtab_iterator_init(&iter, object->symtab, kxld_sym_is_common, FALSE); - while ((sym = kxld_symtab_iterator_get_next(&iter))) { - align = kxld_sym_get_common_align(sym); - size = kxld_sym_get_common_size(sym); - - if (align > max_align) max_align = align; - - total_size = kxld_align_address(total_size, align) + size; - } - - /* If there are common symbols, grow or create the __DATA __common section - * to hold them. - */ - if (total_size) { - sect = kxld_object_get_sect_by_name(object, SEG_DATA, SECT_COMMON); - if (sect) { - base_addr = sect->base_addr + sect->size; - - kxld_sect_grow(sect, total_size, max_align); - } else { - base_addr = 0; - - rval = add_section(object, §); - require_noerr(rval, finish); - - kxld_sect_init_zerofill(sect, SEG_DATA, SECT_COMMON, - total_size, max_align); - } - - /* Resolve the common symbols against the new section */ - rval = kxld_array_get_index(&object->sects, sect, §num); - require_noerr(rval, finish); - - kxld_symtab_iterator_reset(&iter); - while ((sym = kxld_symtab_iterator_get_next(&iter))) { - align = kxld_sym_get_common_align(sym); - size = kxld_sym_get_common_size(sym); - - base_addr = kxld_align_address(base_addr, align); - kxld_sym_resolve_common(sym, sectnum, base_addr); - - base_addr += size; - } - } - - rval = KERN_SUCCESS; + kern_return_t rval = KERN_FAILURE; + KXLDSymtabIterator iter; + KXLDSym *sym = NULL; + KXLDSect *sect = NULL; + kxld_addr_t base_addr = 0; + kxld_size_t size = 0; + kxld_size_t total_size = 0; + u_int align = 0; + u_int max_align = 0; + u_int sectnum = 0; + + if (!kxld_object_target_supports_common_symbols(object)) { + rval = KERN_SUCCESS; + goto finish; + } + + /* Iterate over the common symbols to calculate their total aligned size */ + kxld_symtab_iterator_init(&iter, object->symtab, kxld_sym_is_common, FALSE); + while ((sym = kxld_symtab_iterator_get_next(&iter))) { + align = kxld_sym_get_common_align(sym); + size = kxld_sym_get_common_size(sym); + + if (align > max_align) { + max_align = align; + } + + total_size = kxld_align_address(total_size, align) + size; + } + + /* If there are common symbols, grow or create the __DATA __common section + * to hold them. + */ + if (total_size) { + sect = kxld_object_get_sect_by_name(object, SEG_DATA, SECT_COMMON); + if (sect) { + base_addr = sect->base_addr + sect->size; + + kxld_sect_grow(sect, total_size, max_align); + } else { + base_addr = 0; + + rval = add_section(object, §); + require_noerr(rval, finish); + + kxld_sect_init_zerofill(sect, SEG_DATA, SECT_COMMON, + total_size, max_align); + } + + /* Resolve the common symbols against the new section */ + rval = kxld_array_get_index(&object->sects, sect, §num); + require_noerr(rval, finish); + + kxld_symtab_iterator_reset(&iter); + while ((sym = kxld_symtab_iterator_get_next(&iter))) { + align = kxld_sym_get_common_align(sym); + size = kxld_sym_get_common_size(sym); + + base_addr = kxld_align_address(base_addr, align); + kxld_sym_resolve_common(sym, sectnum, base_addr); + + base_addr += size; + } + } + + rval = KERN_SUCCESS; finish: - return rval; + return rval; } #endif /* KXLD_USER_OR_COMMON */ @@ -1518,7 +1561,7 @@ finish: static boolean_t target_has_got(const KXLDObject *object) { - return FALSE: + return FALSE: } /******************************************************************************* @@ -1527,33 +1570,33 @@ target_has_got(const KXLDObject *object) static kern_return_t create_got(KXLDObject *object) { - kern_return_t rval = KERN_FAILURE; - KXLDSect *sect = NULL; - u_int ngots = 0; - u_int i = 0; + kern_return_t rval = KERN_FAILURE; + KXLDSect *sect = NULL; + u_int ngots = 0; + u_int i = 0; - if (!target_has_got(object)) { - rval = KERN_SUCCESS; - goto finish; - } + if (!target_has_got(object)) { + rval = KERN_SUCCESS; + goto finish; + } - for (i = 0; i < object->sects.nitems; ++i) { - sect = kxld_array_get_item(&object->sects, i); - ngots += kxld_sect_get_ngots(sect, &object->relocator, - object->symtab); - } + for (i = 0; i < object->sects.nitems; ++i) { + sect = kxld_array_get_item(&object->sects, i); + ngots += kxld_sect_get_ngots(sect, &object->relocator, + object->symtab); + } - rval = add_section(object, §); - require_noerr(rval, finish); + rval = add_section(object, §); + require_noerr(rval, finish); - rval = kxld_sect_init_got(sect, ngots); - require_noerr(rval, finish); + rval = kxld_sect_init_got(sect, ngots); + require_noerr(rval, finish); - object->got_is_created = TRUE; - rval = KERN_SUCCESS; + object->got_is_created = TRUE; + rval = KERN_SUCCESS; finish: - return rval; + return rval; } /******************************************************************************* @@ -1561,32 +1604,31 @@ finish: static kern_return_t populate_got(KXLDObject *object) { - kern_return_t rval = KERN_FAILURE; - KXLDSect *sect = NULL; - u_int i = 0; + kern_return_t rval = KERN_FAILURE; + KXLDSect *sect = NULL; + u_int i = 0; - if (!target_has_got(object) || !object->got_is_created) { - rval = KERN_SUCCESS; - goto finish; - } + if (!target_has_got(object) || !object->got_is_created) { + rval = KERN_SUCCESS; + goto finish; + } - for (i = 0; i < object->sects.nitems; ++i) { - sect = kxld_array_get_item(&object->sects, i); - if (streq_safe(sect->segname, KXLD_SEG_GOT, sizeof(KXLD_SEG_GOT)) && - streq_safe(sect->sectname, KXLD_SECT_GOT, sizeof(KXLD_SECT_GOT))) - { - kxld_sect_populate_got(sect, object->symtab, - kxld_object_target_needs_swap(object)); - break; - } - } + for (i = 0; i < object->sects.nitems; ++i) { + sect = kxld_array_get_item(&object->sects, i); + if (streq_safe(sect->segname, KXLD_SEG_GOT, sizeof(KXLD_SEG_GOT)) && + streq_safe(sect->sectname, KXLD_SECT_GOT, sizeof(KXLD_SECT_GOT))) { + kxld_sect_populate_got(sect, object->symtab, + kxld_object_target_needs_swap(object)); + break; + } + } - require_action(i < object->sects.nitems, finish, rval=KXLD_MISSING_GOT); + require_action(i < object->sects.nitems, finish, rval = KXLD_MISSING_GOT); - rval = KERN_SUCCESS; + rval = KERN_SUCCESS; finish: - return rval; + return rval; } #endif /* KXLD_USER_OR_GOT */ @@ -1595,10 +1637,10 @@ finish: static boolean_t target_supports_protected_segments(const KXLDObject *object) { - return (object->is_final_image && - (object->cputype == CPU_TYPE_X86_64 || - object->cputype == CPU_TYPE_ARM || - object->cputype == CPU_TYPE_ARM64)); + return object->is_final_image && + (object->cputype == CPU_TYPE_X86_64 || + object->cputype == CPU_TYPE_ARM || + object->cputype == CPU_TYPE_ARM64); } /******************************************************************************* @@ -1606,145 +1648,146 @@ target_supports_protected_segments(const KXLDObject *object) static void set_is_object_linked(KXLDObject *object) { - u_int i = 0; + u_int i = 0; - if (kxld_object_is_kernel(object)) { - object->is_linked = TRUE; - return; - } + if (kxld_object_is_kernel(object)) { + object->is_linked = TRUE; + return; + } - if (object->is_final_image) { - object->is_linked = !object->extrelocs.nitems; - return; - } + if (object->is_final_image) { + object->is_linked = !object->extrelocs.nitems; + return; + } - object->is_linked = TRUE; - for (i = 0; i < object->sects.nitems; ++i) { - KXLDSect *sect = kxld_array_get_item(&object->sects, i); - if (sect->relocs.nitems) { - object->is_linked = FALSE; - break; - } - } + object->is_linked = TRUE; + for (i = 0; i < object->sects.nitems; ++i) { + KXLDSect *sect = kxld_array_get_item(&object->sects, i); + if (sect->relocs.nitems) { + object->is_linked = FALSE; + break; + } + } } /******************************************************************************* *******************************************************************************/ -void kxld_object_clear(KXLDObject *object) +void +kxld_object_clear(KXLDObject *object) { - KXLDSeg *seg = NULL; - KXLDSect *sect = NULL; - u_int i; - u_char *my_file; - - check(object); + KXLDSeg *seg = NULL; + KXLDSect *sect = NULL; + u_int i; + u_char *my_file; + + check(object); - if (isOldInterface) { - my_file = object->file; - } - else { - my_file = object->split_info.kextExecutable; - } + if (isOldInterface) { + my_file = object->file; + } else { + my_file = object->split_info.kextExecutable; + } #if !KERNEL - if (kxld_object_is_kernel(object)) { - unswap_macho(my_file, object->host_order, object->target_order); - } + if (kxld_object_is_kernel(object)) { + unswap_macho(my_file, object->host_order, object->target_order); + } #endif /* !KERNEL */ - for (i = 0; i < object->segs.nitems; ++i) { - seg = kxld_array_get_item(&object->segs, i); - kxld_seg_clear(seg); - } - kxld_array_reset(&object->segs); - - for (i = 0; i < object->sects.nitems; ++i) { - sect = kxld_array_get_item(&object->sects, i); - kxld_sect_clear(sect); - } - kxld_array_reset(&object->sects); - - kxld_array_reset(&object->extrelocs); - kxld_array_reset(&object->locrelocs); - kxld_relocator_clear(&object->relocator); - kxld_uuid_clear(&object->uuid); - kxld_versionmin_clear(&object->versionmin); - kxld_srcversion_clear(&object->srcversion); - - if (object->symtab) kxld_symtab_clear(object->symtab); - - if (isOldInterface) { - object->file = NULL; - object->size = 0; - } - else { - kxld_splitinfolc_clear(&object->splitinfolc); - object->split_info.kextExecutable = NULL; - object->split_info.kextSize = 0; - } - object->filetype = 0; - object->cputype = 0; - object->cpusubtype = 0; - object->is_kernel = FALSE; - object->is_final_image = FALSE; - object->is_linked = FALSE; - object->got_is_created = FALSE; + for (i = 0; i < object->segs.nitems; ++i) { + seg = kxld_array_get_item(&object->segs, i); + kxld_seg_clear(seg); + } + kxld_array_reset(&object->segs); + + for (i = 0; i < object->sects.nitems; ++i) { + sect = kxld_array_get_item(&object->sects, i); + kxld_sect_clear(sect); + } + kxld_array_reset(&object->sects); + + kxld_array_reset(&object->extrelocs); + kxld_array_reset(&object->locrelocs); + kxld_relocator_clear(&object->relocator); + kxld_uuid_clear(&object->uuid); + kxld_versionmin_clear(&object->versionmin); + kxld_srcversion_clear(&object->srcversion); + + if (object->symtab) { + kxld_symtab_clear(object->symtab); + } + + if (isOldInterface) { + object->file = NULL; + object->size = 0; + } else { + kxld_splitinfolc_clear(&object->splitinfolc); + object->split_info.kextExecutable = NULL; + object->split_info.kextSize = 0; + } + object->filetype = 0; + object->cputype = 0; + object->cpusubtype = 0; + object->is_kernel = FALSE; + object->is_final_image = FALSE; + object->is_linked = FALSE; + object->got_is_created = FALSE; #if KXLD_USER_OR_OBJECT - object->section_order = NULL; + object->section_order = NULL; #endif #if !KERNEL - object->host_order = 0; - object->target_order = 0; + object->host_order = 0; + object->target_order = 0; #endif } /******************************************************************************* *******************************************************************************/ -void kxld_object_deinit(KXLDObject *object __unused) +void +kxld_object_deinit(KXLDObject *object __unused) { - KXLDSeg *seg = NULL; - KXLDSect *sect = NULL; - u_int i; - u_char *my_file; - - check(object); - - if (isOldInterface) { - my_file = object->file; - } - else { - my_file = object->split_info.kextExecutable; - } + KXLDSeg *seg = NULL; + KXLDSect *sect = NULL; + u_int i; + u_char *my_file; + + check(object); + + if (isOldInterface) { + my_file = object->file; + } else { + my_file = object->split_info.kextExecutable; + } #if !KERNEL - if (my_file && kxld_object_is_kernel(object)) { - unswap_macho(my_file, object->host_order, object->target_order); - } + if (my_file && kxld_object_is_kernel(object)) { + unswap_macho(my_file, object->host_order, object->target_order); + } #endif /* !KERNEL */ - for (i = 0; i < object->segs.maxitems; ++i) { - seg = kxld_array_get_slot(&object->segs, i); - kxld_seg_deinit(seg); - } - kxld_array_deinit(&object->segs); + for (i = 0; i < object->segs.maxitems; ++i) { + seg = kxld_array_get_slot(&object->segs, i); + kxld_seg_deinit(seg); + } + kxld_array_deinit(&object->segs); - for (i = 0; i < object->sects.maxitems; ++i) { - sect = kxld_array_get_slot(&object->sects, i); - kxld_sect_deinit(sect); - } - kxld_array_deinit(&object->sects); + for (i = 0; i < object->sects.maxitems; ++i) { + sect = kxld_array_get_slot(&object->sects, i); + kxld_sect_deinit(sect); + } + kxld_array_deinit(&object->sects); - kxld_array_deinit(&object->extrelocs); - kxld_array_deinit(&object->locrelocs); + kxld_array_deinit(&object->extrelocs); + kxld_array_deinit(&object->locrelocs); - if (object->symtab) { - kxld_symtab_deinit(object->symtab); - kxld_free(object->symtab, kxld_symtab_sizeof()); - } + if (object->symtab) { + kxld_symtab_deinit(object->symtab); + kxld_free(object->symtab, kxld_symtab_sizeof()); + } - bzero(object, sizeof(*object)); + bzero(object, sizeof(*object)); } /******************************************************************************* @@ -1752,18 +1795,17 @@ void kxld_object_deinit(KXLDObject *object __unused) const u_char * kxld_object_get_file(const KXLDObject *object) { - const u_char *my_file; - - check(object); + const u_char *my_file; + + check(object); - if (isOldInterface) { - my_file = object->file; - } - else { - my_file = object->split_info.kextExecutable; - } - - return my_file; + if (isOldInterface) { + my_file = object->file; + } else { + my_file = object->split_info.kextExecutable; + } + + return my_file; } /******************************************************************************* @@ -1771,49 +1813,49 @@ kxld_object_get_file(const KXLDObject *object) const char * kxld_object_get_name(const KXLDObject *object) { - check(object); + check(object); - return object->name; + return object->name; } /******************************************************************************* *******************************************************************************/ -boolean_t +boolean_t kxld_object_is_32_bit(const KXLDObject *object) { - check(object); + check(object); - return kxld_is_32_bit(object->cputype); + return kxld_is_32_bit(object->cputype); } /******************************************************************************* *******************************************************************************/ -boolean_t +boolean_t kxld_object_is_final_image(const KXLDObject *object) { - check(object); + check(object); - return object->is_final_image; + return object->is_final_image; } /******************************************************************************* *******************************************************************************/ -boolean_t +boolean_t kxld_object_is_kernel(const KXLDObject *object) { - check(object); + check(object); - return object->is_kernel; + return object->is_kernel; } /******************************************************************************* *******************************************************************************/ -boolean_t +boolean_t kxld_object_is_linked(const KXLDObject *object) { - check(object); + check(object); - return object->is_linked; + return object->is_linked; } /******************************************************************************* @@ -1821,9 +1863,9 @@ kxld_object_is_linked(const KXLDObject *object) boolean_t kxld_object_target_supports_strict_patching(const KXLDObject *object) { - check(object); + check(object); - return (object->cputype != CPU_TYPE_I386); + return object->cputype != CPU_TYPE_I386; } /******************************************************************************* @@ -1831,220 +1873,216 @@ kxld_object_target_supports_strict_patching(const KXLDObject *object) boolean_t kxld_object_target_supports_common_symbols(const KXLDObject *object) { - check(object); + check(object); - return (object->cputype == CPU_TYPE_I386); + return object->cputype == CPU_TYPE_I386; } /******************************************************************************* - *******************************************************************************/ +*******************************************************************************/ void kxld_object_get_vmsize_for_seg_by_name(const KXLDObject *object, - const char *segname, - u_long *vmsize) + const char *segname, + u_long *vmsize) { - check(object); - check(segname); - check(vmsize); + check(object); + check(segname); + check(vmsize); + + KXLDSeg *seg = NULL; + u_long my_size = 0; + + /* segment vmsize */ + seg = kxld_object_get_seg_by_name(object, segname); - KXLDSeg *seg = NULL; - u_long my_size = 0; + my_size = (u_long) kxld_seg_get_vmsize(seg); - /* segment vmsize */ - seg = kxld_object_get_seg_by_name(object, segname); - - my_size = (u_long) kxld_seg_get_vmsize(seg); - #if KXLD_PIC_KEXTS - if (kxld_seg_is_linkedit_seg(seg)) - { - u_long reloc_size = 0; - - if (target_supports_slideable_kexts(object)) { - /* get size of __DYSYMTAB relocation entries */ - reloc_size = kxld_reloc_get_macho_data_size(&object->locrelocs, &object->extrelocs); - my_size += reloc_size; - } - } + if (kxld_seg_is_linkedit_seg(seg)) { + u_long reloc_size = 0; + + if (target_supports_slideable_kexts(object)) { + /* get size of __DYSYMTAB relocation entries */ + reloc_size = kxld_reloc_get_macho_data_size(&object->locrelocs, &object->extrelocs); + my_size += reloc_size; + } + } #endif - - *vmsize = my_size; + + *vmsize = my_size; } /******************************************************************************* *******************************************************************************/ void -kxld_object_get_vmsize(const KXLDObject *object, u_long *header_size, +kxld_object_get_vmsize(const KXLDObject *object, u_long *header_size, u_long *vmsize) { - check(object); - check(header_size); - check(vmsize); - *header_size = 0; - *vmsize = 0; + check(object); + check(header_size); + check(vmsize); + *header_size = 0; + *vmsize = 0; - /* vmsize is the padded header page(s) + segment vmsizes */ + /* vmsize is the padded header page(s) + segment vmsizes */ - *header_size = (object->is_final_image) ? - 0 : (u_long)kxld_round_page_cross_safe(get_macho_header_size(object)); - - *vmsize = *header_size + get_macho_data_size(object); + *header_size = (object->is_final_image) ? + 0 : (u_long)kxld_round_page_cross_safe(get_macho_header_size(object)); + *vmsize = *header_size + get_macho_data_size(object); } /******************************************************************************* - *******************************************************************************/ +*******************************************************************************/ void kxld_object_set_linked_object_size(KXLDObject *object, u_long vmsize) { - check(object); - - if (isOldInterface) { - object->output_buffer_size = vmsize; /* cache this for use later */ - } - else { - object->split_info.linkedKextSize = vmsize; - } - return; -} - -/******************************************************************************* -*******************************************************************************/ -kern_return_t -kxld_object_export_linked_object(const KXLDObject *object, - void *linked_object - ) -{ - kern_return_t rval = KERN_FAILURE; - KXLDSeg *seg = NULL; - u_long size = 0; - u_long header_size = 0; - u_long header_offset = 0; - u_long data_offset = 0; - u_int ncmds = 0; - u_int i = 0; - boolean_t is_32bit_object = kxld_object_is_32_bit(object); - kxld_addr_t link_addr; - u_char *my_linked_object; - - check(object); - check(linked_object); - - if (isOldInterface) { - size = object->output_buffer_size; - link_addr = object->link_addr; - my_linked_object = (u_char *) linked_object; - } - else { - size = ((splitKextLinkInfo *)linked_object)->linkedKextSize; - link_addr = ((splitKextLinkInfo *)linked_object)->vmaddr_TEXT; - my_linked_object = ((splitKextLinkInfo *)linked_object)->linkedKext; - } - - /* Calculate the size of the headers and data */ - - header_size = get_macho_header_size(object); - - /* Copy data to the file */ - - ncmds = object->segs.nitems + 1 /* LC_SYMTAB */; + check(object); + + if (isOldInterface) { + object->output_buffer_size = vmsize; /* cache this for use later */ + } else { + object->split_info.linkedKextSize = vmsize; + } + return; +} + +/******************************************************************************* +*******************************************************************************/ +kern_return_t +kxld_object_export_linked_object(const KXLDObject *object, + void *linked_object + ) +{ + kern_return_t rval = KERN_FAILURE; + KXLDSeg *seg = NULL; + u_long size = 0; + u_long header_size = 0; + u_long header_offset = 0; + u_long data_offset = 0; + u_int ncmds = 0; + u_int i = 0; + boolean_t is_32bit_object = kxld_object_is_32_bit(object); + kxld_addr_t link_addr; + u_char *my_linked_object; + + check(object); + check(linked_object); + + if (isOldInterface) { + size = object->output_buffer_size; + link_addr = object->link_addr; + my_linked_object = (u_char *) linked_object; + } else { + size = ((splitKextLinkInfo *)linked_object)->linkedKextSize; + link_addr = ((splitKextLinkInfo *)linked_object)->vmaddr_TEXT; + my_linked_object = ((splitKextLinkInfo *)linked_object)->linkedKext; + } + + /* Calculate the size of the headers and data */ + + header_size = get_macho_header_size(object); + + /* Copy data to the file */ + + ncmds = object->segs.nitems + 1 /* LC_SYMTAB */; #if KXLD_PIC_KEXTS - /* don't write out a DYSYMTAB segment for targets that can't digest it - */ - if (target_supports_slideable_kexts(object)) { - ncmds++; /* dysymtab */ - } -#endif /* KXLD_PIC_KEXTS */ - - if (object->uuid.has_uuid == TRUE) { - ncmds++; - } - - if (object->versionmin.has_versionmin == TRUE) { - ncmds++; - } - - if (object->srcversion.has_srcversion == TRUE) { - ncmds++; - } - - if (isSplitKext && object->splitinfolc.has_splitinfolc) { - ncmds++; - } - - rval = export_macho_header(object, my_linked_object, ncmds, &header_offset, header_size); - require_noerr(rval, finish); - - for (i = 0; i < object->segs.nitems; ++i) { - seg = kxld_array_get_item(&object->segs, i); - - rval = kxld_seg_export_macho_to_vm(seg, my_linked_object, &header_offset, - header_size, size, link_addr, is_32bit_object); - require_noerr(rval, finish); - } - - seg = kxld_object_get_seg_by_name(object, SEG_LINKEDIT); - data_offset = (u_long) (seg->link_addr - link_addr); - - // data_offset is used to set the fileoff in the macho header load commands - rval = kxld_symtab_export_macho(object->symtab, - my_linked_object, - &header_offset, - header_size, - &data_offset, size, is_32bit_object); - require_noerr(rval, finish); - - // data_offset now points past the symbol tab and strings data in the linkedit - // segment - (it was used to set new values for symoff and stroff) + /* don't write out a DYSYMTAB segment for targets that can't digest it + */ + if (target_supports_slideable_kexts(object)) { + ncmds++; /* dysymtab */ + } +#endif /* KXLD_PIC_KEXTS */ + + if (object->uuid.has_uuid == TRUE) { + ncmds++; + } + + if (object->versionmin.has_versionmin == TRUE) { + ncmds++; + } + + if (object->srcversion.has_srcversion == TRUE) { + ncmds++; + } + + if (isSplitKext && object->splitinfolc.has_splitinfolc) { + ncmds++; + } + + rval = export_macho_header(object, my_linked_object, ncmds, &header_offset, header_size); + require_noerr(rval, finish); + + for (i = 0; i < object->segs.nitems; ++i) { + seg = kxld_array_get_item(&object->segs, i); + + rval = kxld_seg_export_macho_to_vm(seg, my_linked_object, &header_offset, + header_size, size, link_addr, is_32bit_object); + require_noerr(rval, finish); + } + + seg = kxld_object_get_seg_by_name(object, SEG_LINKEDIT); + data_offset = (u_long) (seg->link_addr - link_addr); + + // data_offset is used to set the fileoff in the macho header load commands + rval = kxld_symtab_export_macho(object->symtab, + my_linked_object, + &header_offset, + header_size, + &data_offset, size, is_32bit_object); + require_noerr(rval, finish); + + // data_offset now points past the symbol tab and strings data in the linkedit + // segment - (it was used to set new values for symoff and stroff) #if KXLD_PIC_KEXTS - if (target_supports_slideable_kexts(object)) { - rval = kxld_reloc_export_macho(&object->relocator, - &object->locrelocs, - &object->extrelocs, - my_linked_object, - &header_offset, - header_size, - &data_offset, size); - require_noerr(rval, finish); - } -#endif /* KXLD_PIC_KEXTS */ - - if (object->uuid.has_uuid) { - rval = kxld_uuid_export_macho(&object->uuid, my_linked_object, &header_offset, header_size); - require_noerr(rval, finish); - } - - if (object->versionmin.has_versionmin) { - rval = kxld_versionmin_export_macho(&object->versionmin, my_linked_object, &header_offset, header_size); - require_noerr(rval, finish); - } - - if (object->srcversion.has_srcversion) { - rval = kxld_srcversion_export_macho(&object->srcversion, my_linked_object, &header_offset, header_size); - require_noerr(rval, finish); - } - - if (isSplitKext && object->splitinfolc.has_splitinfolc) { - rval = kxld_splitinfolc_export_macho(&object->splitinfolc, - linked_object, - &header_offset, - header_size, - &data_offset, - size); - require_noerr(rval, finish); - } + if (target_supports_slideable_kexts(object)) { + rval = kxld_reloc_export_macho(&object->relocator, + &object->locrelocs, + &object->extrelocs, + my_linked_object, + &header_offset, + header_size, + &data_offset, size); + require_noerr(rval, finish); + } +#endif /* KXLD_PIC_KEXTS */ + + if (object->uuid.has_uuid) { + rval = kxld_uuid_export_macho(&object->uuid, my_linked_object, &header_offset, header_size); + require_noerr(rval, finish); + } + + if (object->versionmin.has_versionmin) { + rval = kxld_versionmin_export_macho(&object->versionmin, my_linked_object, &header_offset, header_size); + require_noerr(rval, finish); + } + + if (object->srcversion.has_srcversion) { + rval = kxld_srcversion_export_macho(&object->srcversion, my_linked_object, &header_offset, header_size); + require_noerr(rval, finish); + } + + if (isSplitKext && object->splitinfolc.has_splitinfolc) { + rval = kxld_splitinfolc_export_macho(&object->splitinfolc, + linked_object, + &header_offset, + header_size, + &data_offset, + size); + require_noerr(rval, finish); + } #if !KERNEL - unswap_macho(my_linked_object, object->host_order, object->target_order); + unswap_macho(my_linked_object, object->host_order, object->target_order); #endif /* KERNEL */ - rval = KERN_SUCCESS; + rval = KERN_SUCCESS; finish: - return rval; + return rval; } /******************************************************************************* @@ -2053,21 +2091,21 @@ static kern_return_t export_macho_header(const KXLDObject *object, u_char *buf, u_int ncmds, u_long *header_offset, u_long header_size) { - kern_return_t rval = KERN_FAILURE; + kern_return_t rval = KERN_FAILURE; - check(object); - check(buf); - check(header_offset); + check(object); + check(buf); + check(header_offset); - KXLD_3264_FUNC(kxld_object_is_32_bit(object), rval, - export_macho_header_32, export_macho_header_64, - object, buf, ncmds, header_offset, header_size); - require_noerr(rval, finish); + KXLD_3264_FUNC(kxld_object_is_32_bit(object), rval, + export_macho_header_32, export_macho_header_64, + object, buf, ncmds, header_offset, header_size); + require_noerr(rval, finish); - rval = KERN_SUCCESS; + rval = KERN_SUCCESS; finish: - return rval; + return rval; } #if KXLD_USER_OR_ILP32 @@ -2077,31 +2115,31 @@ static kern_return_t export_macho_header_32(const KXLDObject *object, u_char *buf, u_int ncmds, u_long *header_offset, u_long header_size) { - kern_return_t rval = KERN_FAILURE; - struct mach_header *mach = NULL; - - check(object); - check(buf); - check(header_offset); - - require_action(sizeof(*mach) <= header_size - *header_offset, finish, - rval=KERN_FAILURE); - mach = (struct mach_header *) ((void *) (buf + *header_offset)); - - mach->magic = MH_MAGIC; - mach->cputype = object->cputype; - mach->cpusubtype = object->cpusubtype; - mach->filetype = object->filetype; - mach->ncmds = ncmds; - mach->sizeofcmds = (uint32_t) (header_size - sizeof(*mach)); - mach->flags = MH_NOUNDEFS; - - *header_offset += sizeof(*mach); - - rval = KERN_SUCCESS; + kern_return_t rval = KERN_FAILURE; + struct mach_header *mach = NULL; + + check(object); + check(buf); + check(header_offset); + + require_action(sizeof(*mach) <= header_size - *header_offset, finish, + rval = KERN_FAILURE); + mach = (struct mach_header *) ((void *) (buf + *header_offset)); + + mach->magic = MH_MAGIC; + mach->cputype = object->cputype; + mach->cpusubtype = object->cpusubtype; + mach->filetype = object->filetype; + mach->ncmds = ncmds; + mach->sizeofcmds = (uint32_t) (header_size - sizeof(*mach)); + mach->flags = MH_NOUNDEFS; + + *header_offset += sizeof(*mach); + + rval = KERN_SUCCESS; finish: - return rval; + return rval; } #endif /* KXLD_USER_OR_ILP32 */ @@ -2112,90 +2150,90 @@ static kern_return_t export_macho_header_64(const KXLDObject *object, u_char *buf, u_int ncmds, u_long *header_offset, u_long header_size) { - kern_return_t rval = KERN_FAILURE; - struct mach_header_64 *mach = NULL; - - check(object); - check(buf); - check(header_offset); - - require_action(sizeof(*mach) <= header_size - *header_offset, finish, - rval=KERN_FAILURE); - mach = (struct mach_header_64 *) ((void *) (buf + *header_offset)); - - mach->magic = MH_MAGIC_64; - mach->cputype = object->cputype; - mach->cpusubtype = object->cpusubtype; - mach->filetype = object->filetype; - mach->ncmds = ncmds; - mach->sizeofcmds = (uint32_t) (header_size - sizeof(*mach)); - mach->flags = MH_NOUNDEFS; - - *header_offset += sizeof(*mach); - + kern_return_t rval = KERN_FAILURE; + struct mach_header_64 *mach = NULL; + + check(object); + check(buf); + check(header_offset); + + require_action(sizeof(*mach) <= header_size - *header_offset, finish, + rval = KERN_FAILURE); + mach = (struct mach_header_64 *) ((void *) (buf + *header_offset)); + + mach->magic = MH_MAGIC_64; + mach->cputype = object->cputype; + mach->cpusubtype = object->cpusubtype; + mach->filetype = object->filetype; + mach->ncmds = ncmds; + mach->sizeofcmds = (uint32_t) (header_size - sizeof(*mach)); + mach->flags = MH_NOUNDEFS; + + *header_offset += sizeof(*mach); + #if SPLIT_KEXTS_DEBUG - { - kxld_log(kKxldLogLinking, kKxldLogErr, - " %p >>> Start of macho header (size %lu) <%s>", - (void *) mach, - sizeof(*mach), - __func__); - kxld_log(kKxldLogLinking, kKxldLogErr, - " %p <<< End of macho header <%s>", - (void *) ((u_char *)mach + sizeof(*mach)), - __func__); - } + { + kxld_log(kKxldLogLinking, kKxldLogErr, + " %p >>> Start of macho header (size %lu) <%s>", + (void *) mach, + sizeof(*mach), + __func__); + kxld_log(kKxldLogLinking, kKxldLogErr, + " %p <<< End of macho header <%s>", + (void *) ((u_char *)mach + sizeof(*mach)), + __func__); + } #endif - - rval = KERN_SUCCESS; + + rval = KERN_SUCCESS; finish: - return rval; + return rval; } #endif /* KXLD_USER_OR_LP64 */ /******************************************************************************* *******************************************************************************/ -kern_return_t +kern_return_t kxld_object_index_symbols_by_name(KXLDObject *object) { - return kxld_symtab_index_symbols_by_name(object->symtab); + return kxld_symtab_index_symbols_by_name(object->symtab); } /******************************************************************************* *******************************************************************************/ -kern_return_t +kern_return_t kxld_object_index_cxx_symbols_by_value(KXLDObject *object) { - return kxld_symtab_index_cxx_symbols_by_value(object->symtab); + return kxld_symtab_index_cxx_symbols_by_value(object->symtab); } /******************************************************************************* *******************************************************************************/ -kern_return_t +kern_return_t kxld_object_relocate(KXLDObject *object, kxld_addr_t link_address) { - kern_return_t rval = KERN_FAILURE; - KXLDSeg *seg = NULL; - u_int i = 0; + kern_return_t rval = KERN_FAILURE; + KXLDSeg *seg = NULL; + u_int i = 0; - check(object); + check(object); - object->link_addr = link_address; + object->link_addr = link_address; - /* Relocate segments (which relocates the sections) */ - for (i = 0; i < object->segs.nitems; ++i) { - seg = kxld_array_get_item(&object->segs, i); - kxld_seg_relocate(seg, link_address); - } // for... + /* Relocate segments (which relocates the sections) */ + for (i = 0; i < object->segs.nitems; ++i) { + seg = kxld_array_get_item(&object->segs, i); + kxld_seg_relocate(seg, link_address); + } // for... - /* Relocate symbols */ - rval = kxld_symtab_relocate(object->symtab, &object->sects); - require_noerr(rval, finish); + /* Relocate symbols */ + rval = kxld_symtab_relocate(object->symtab, &object->sects); + require_noerr(rval, finish); - rval = KERN_SUCCESS; + rval = KERN_SUCCESS; finish: - return rval; + return rval; } /******************************************************************************* @@ -2203,126 +2241,126 @@ finish: static KXLDSym * get_mutable_sym(const KXLDObject *object, const KXLDSym *sym) { - KXLDSym *rval = NULL; - kern_return_t result = KERN_FAILURE; - u_int i = 0; + KXLDSym *rval = NULL; + kern_return_t result = KERN_FAILURE; + u_int i = 0; - result = kxld_symtab_get_sym_index(object->symtab, sym, &i); - require_noerr(result, finish); + result = kxld_symtab_get_sym_index(object->symtab, sym, &i); + require_noerr(result, finish); - rval = kxld_symtab_get_symbol_by_index(object->symtab, i); - require_action(rval == sym, finish, rval=NULL); + rval = kxld_symtab_get_symbol_by_index(object->symtab, i); + require_action(rval == sym, finish, rval = NULL); finish: - return rval; + return rval; } /******************************************************************************* *******************************************************************************/ -kern_return_t -kxld_object_resolve_symbol(KXLDObject *object, +kern_return_t +kxld_object_resolve_symbol(KXLDObject *object, const KXLDSym *sym, kxld_addr_t addr) { - kern_return_t rval = KERN_FAILURE; - KXLDSym *resolved_sym = NULL; + kern_return_t rval = KERN_FAILURE; + KXLDSym *resolved_sym = NULL; - resolved_sym = get_mutable_sym(object, sym); - require_action(resolved_sym, finish, rval=KERN_FAILURE); + resolved_sym = get_mutable_sym(object, sym); + require_action(resolved_sym, finish, rval = KERN_FAILURE); - rval = kxld_sym_resolve(resolved_sym, addr); - require_noerr(rval, finish); + rval = kxld_sym_resolve(resolved_sym, addr); + require_noerr(rval, finish); - rval = KERN_SUCCESS; + rval = KERN_SUCCESS; finish: - return rval; + return rval; } /******************************************************************************* *******************************************************************************/ -kern_return_t +kern_return_t kxld_object_patch_symbol(KXLDObject *object, const struct kxld_sym *sym) { - kern_return_t rval = KERN_FAILURE; - KXLDSym *patched_sym = NULL; + kern_return_t rval = KERN_FAILURE; + KXLDSym *patched_sym = NULL; - patched_sym = get_mutable_sym(object, sym); - require_action(patched_sym, finish, rval=KERN_FAILURE); + patched_sym = get_mutable_sym(object, sym); + require_action(patched_sym, finish, rval = KERN_FAILURE); - (void) kxld_sym_patch(patched_sym); - rval = KERN_SUCCESS; + (void) kxld_sym_patch(patched_sym); + rval = KERN_SUCCESS; finish: - return rval; + return rval; } /******************************************************************************* *******************************************************************************/ -kern_return_t -kxld_object_add_symbol(KXLDObject *object, char *name, kxld_addr_t link_addr, +kern_return_t +kxld_object_add_symbol(KXLDObject *object, char *name, kxld_addr_t link_addr, const KXLDSym **sym_out) { - kern_return_t rval = KERN_FAILURE; - KXLDSym *sym = NULL; + kern_return_t rval = KERN_FAILURE; + KXLDSym *sym = NULL; - rval = kxld_symtab_add_symbol(object->symtab, name, link_addr, &sym); - require_noerr(rval, finish); + rval = kxld_symtab_add_symbol(object->symtab, name, link_addr, &sym); + require_noerr(rval, finish); - *sym_out = sym; - rval = KERN_SUCCESS; + *sym_out = sym; + rval = KERN_SUCCESS; finish: - return rval; + return rval; } /******************************************************************************* *******************************************************************************/ -kern_return_t -kxld_object_process_relocations(KXLDObject *object, +kern_return_t +kxld_object_process_relocations(KXLDObject *object, const KXLDDict *patched_vtables) { - kern_return_t rval = KERN_FAILURE; - - (void) kxld_relocator_set_vtables(&object->relocator, patched_vtables); - - /* Process relocation entries and populate the global offset table. - * - * For final linked images: the relocation entries are contained in a couple - * of tables hanging off the end of the symbol table. The GOT has its own - * section created by the linker; we simply need to fill it. - * - * For object files: the relocation entries are bound to each section. - * The GOT, if it exists for the target architecture, is created by kxld, - * and we must populate it according to our internal structures. - */ - if (object->is_final_image) { + kern_return_t rval = KERN_FAILURE; + + (void) kxld_relocator_set_vtables(&object->relocator, patched_vtables); + + /* Process relocation entries and populate the global offset table. + * + * For final linked images: the relocation entries are contained in a couple + * of tables hanging off the end of the symbol table. The GOT has its own + * section created by the linker; we simply need to fill it. + * + * For object files: the relocation entries are bound to each section. + * The GOT, if it exists for the target architecture, is created by kxld, + * and we must populate it according to our internal structures. + */ + if (object->is_final_image) { #if KXLD_USER_OR_BUNDLE - rval = process_symbol_pointers(object); - require_noerr(rval, finish); + rval = process_symbol_pointers(object); + require_noerr(rval, finish); - rval = process_relocs_from_tables(object); - require_noerr(rval, finish); + rval = process_relocs_from_tables(object); + require_noerr(rval, finish); #else - require_action(FALSE, finish, rval=KERN_FAILURE); + require_action(FALSE, finish, rval = KERN_FAILURE); #endif /* KXLD_USER_OR_BUNDLE */ - } else { + } else { #if KXLD_USER_OR_GOT - /* Populate GOT */ - rval = populate_got(object); - require_noerr(rval, finish); + /* Populate GOT */ + rval = populate_got(object); + require_noerr(rval, finish); #endif /* KXLD_USER_OR_GOT */ #if KXLD_USER_OR_OBJECT - rval = process_relocs_from_sections(object); - require_noerr(rval, finish); + rval = process_relocs_from_sections(object); + require_noerr(rval, finish); #else - require_action(FALSE, finish, rval=KERN_FAILURE); + require_action(FALSE, finish, rval = KERN_FAILURE); #endif /* KXLD_USER_OR_OBJECT */ - } + } - /* Populate kmod info structure */ - rval = populate_kmod_info(object); - require_noerr(rval, finish); - - rval = KERN_SUCCESS; + /* Populate kmod info structure */ + rval = populate_kmod_info(object); + require_noerr(rval, finish); + + rval = KERN_SUCCESS; finish: - return rval; + return rval; } #if KXLD_USER_OR_BUNDLE @@ -2343,92 +2381,91 @@ static boolean_t kxld_show_ptr_value; static kern_return_t process_symbol_pointers(KXLDObject *object) { - kern_return_t rval = KERN_FAILURE; - KXLDSect *sect = NULL; - KXLDSym *sym = NULL; - int32_t *symidx = NULL; - u_char *symptr = NULL; - u_long symptrsize = 0; - u_int nsyms = 0; - u_int firstsym = 0; - u_int i = 0; - - check(object); - - require_action(object->is_final_image && object->dysymtab_hdr, - finish, rval=KERN_FAILURE); - - /* Get the __DATA,__nl_symbol_ptr section. If it doesn't exist, we have - * nothing to do. - */ - - sect = kxld_object_get_sect_by_name(object, SEG_DATA, SECT_SYM_PTRS); - if (!sect || !(sect->flags & S_NON_LAZY_SYMBOL_POINTERS)) { - rval = KERN_SUCCESS; - goto finish; - } - - /* Calculate the table offset and number of entries in the section */ - - if (kxld_object_is_32_bit(object)) { - symptrsize = sizeof(uint32_t); - } else { - symptrsize = sizeof(uint64_t); - } - - nsyms = (u_int) (sect->size / symptrsize); - firstsym = sect->reserved1; - - require_action(firstsym + nsyms <= object->dysymtab_hdr->nindirectsyms, - finish, rval=KERN_FAILURE; - kxld_log(kKxldLogLinking, kKxldLogErr, kKxldLogMalformedMachO - "firstsym + nsyms > object->dysymtab_hdr->nindirectsyms")); - - /* Iterate through the indirect symbol table and fill in the section of - * symbol pointers. There are three cases: - * 1) A normal symbol - put its value directly in the table - * 2) An INDIRECT_SYMBOL_LOCAL - symbols that are local and already have - * their offset from the start of the file in the section. Simply - * add the file's link address to fill this entry. - * 3) An INDIRECT_SYMBOL_ABS - prepopulated absolute symbols. No - * action is required. - */ - - if (isOldInterface) { - symidx = (int32_t *) ((void *) (object->file + object->dysymtab_hdr->indirectsymoff)); - } - else { - symidx = (int32_t *) ((void *) (object->split_info.kextExecutable + object->dysymtab_hdr->indirectsymoff)); - } - - symidx += firstsym; - symptr = sect->data; - for (i = 0; i < nsyms; ++i, ++symidx, symptr+=symptrsize) { - if (*symidx & INDIRECT_SYMBOL_LOCAL) { - if (*symidx & INDIRECT_SYMBOL_ABS) continue; - - if (isOldInterface) { - add_to_ptr(symptr, object->link_addr, kxld_object_is_32_bit(object)); - } - else { - add_to_ptr(symptr, object->split_info.vmaddr_TEXT, kxld_object_is_32_bit(object)); - } - } else { - sym = kxld_symtab_get_symbol_by_index(object->symtab, *symidx); - require_action(sym, finish, rval=KERN_FAILURE); - - if (isOldInterface) { - add_to_ptr(symptr, sym->link_addr, kxld_object_is_32_bit(object)); - } - else { - add_to_ptr(symptr, object->split_info.vmaddr_TEXT, kxld_object_is_32_bit(object)); - } - } - } - - rval = KERN_SUCCESS; + kern_return_t rval = KERN_FAILURE; + KXLDSect *sect = NULL; + KXLDSym *sym = NULL; + int32_t *symidx = NULL; + u_char *symptr = NULL; + u_long symptrsize = 0; + u_int nsyms = 0; + u_int firstsym = 0; + u_int i = 0; + + check(object); + + require_action(object->is_final_image && object->dysymtab_hdr, + finish, rval = KERN_FAILURE); + + /* Get the __DATA,__nl_symbol_ptr section. If it doesn't exist, we have + * nothing to do. + */ + + sect = kxld_object_get_sect_by_name(object, SEG_DATA, SECT_SYM_PTRS); + if (!sect || !(sect->flags & S_NON_LAZY_SYMBOL_POINTERS)) { + rval = KERN_SUCCESS; + goto finish; + } + + /* Calculate the table offset and number of entries in the section */ + + if (kxld_object_is_32_bit(object)) { + symptrsize = sizeof(uint32_t); + } else { + symptrsize = sizeof(uint64_t); + } + + nsyms = (u_int) (sect->size / symptrsize); + firstsym = sect->reserved1; + + require_action(firstsym + nsyms <= object->dysymtab_hdr->nindirectsyms, + finish, rval = KERN_FAILURE; + kxld_log(kKxldLogLinking, kKxldLogErr, kKxldLogMalformedMachO + "firstsym + nsyms > object->dysymtab_hdr->nindirectsyms")); + + /* Iterate through the indirect symbol table and fill in the section of + * symbol pointers. There are three cases: + * 1) A normal symbol - put its value directly in the table + * 2) An INDIRECT_SYMBOL_LOCAL - symbols that are local and already have + * their offset from the start of the file in the section. Simply + * add the file's link address to fill this entry. + * 3) An INDIRECT_SYMBOL_ABS - prepopulated absolute symbols. No + * action is required. + */ + + if (isOldInterface) { + symidx = (int32_t *) ((void *) (object->file + object->dysymtab_hdr->indirectsymoff)); + } else { + symidx = (int32_t *) ((void *) (object->split_info.kextExecutable + object->dysymtab_hdr->indirectsymoff)); + } + + symidx += firstsym; + symptr = sect->data; + for (i = 0; i < nsyms; ++i, ++symidx, symptr += symptrsize) { + if (*symidx & INDIRECT_SYMBOL_LOCAL) { + if (*symidx & INDIRECT_SYMBOL_ABS) { + continue; + } + + if (isOldInterface) { + add_to_ptr(symptr, object->link_addr, kxld_object_is_32_bit(object)); + } else { + add_to_ptr(symptr, object->split_info.vmaddr_TEXT, kxld_object_is_32_bit(object)); + } + } else { + sym = kxld_symtab_get_symbol_by_index(object->symtab, *symidx); + require_action(sym, finish, rval = KERN_FAILURE); + + if (isOldInterface) { + add_to_ptr(symptr, sym->link_addr, kxld_object_is_32_bit(object)); + } else { + add_to_ptr(symptr, object->split_info.vmaddr_TEXT, kxld_object_is_32_bit(object)); + } + } + } + + rval = KERN_SUCCESS; finish: - return rval; + return rval; } /******************************************************************************* @@ -2436,20 +2473,22 @@ finish: static KXLDSeg * get_seg_by_base_addr(KXLDObject *object, kxld_addr_t base_addr) { - KXLDSeg *seg = NULL; - kxld_addr_t start = 0; - kxld_addr_t end = 0; - u_int i = 0; + KXLDSeg *seg = NULL; + kxld_addr_t start = 0; + kxld_addr_t end = 0; + u_int i = 0; - for (i = 0; i < object->segs.nitems; ++i) { - seg = kxld_array_get_item(&object->segs, i); - start = seg->base_addr; - end = seg->base_addr + seg->vmsize; + for (i = 0; i < object->segs.nitems; ++i) { + seg = kxld_array_get_item(&object->segs, i); + start = seg->base_addr; + end = seg->base_addr + seg->vmsize; - if (start <= base_addr && base_addr < end) return seg; - } + if (start <= base_addr && base_addr < end) { + return seg; + } + } - return NULL; + return NULL; } /******************************************************************************* @@ -2457,90 +2496,80 @@ get_seg_by_base_addr(KXLDObject *object, kxld_addr_t base_addr) static kern_return_t process_relocs_from_tables(KXLDObject *object) { - kern_return_t rval = KERN_FAILURE; - KXLDReloc *reloc = NULL; - KXLDSeg *seg = NULL; - u_int i = 0; - - /* Process external relocations */ - for (i = 0; i < object->extrelocs.nitems; ++i) { - reloc = kxld_array_get_item(&object->extrelocs, i); - - seg = get_seg_by_base_addr(object, reloc->address); - require_action(seg, finish, rval=KERN_FAILURE); - - if (isOldInterface) { - rval = kxld_relocator_process_table_reloc(&object->relocator, reloc, - seg, object->link_addr); - } - else { - kxld_addr_t my_link_addr = object->split_info.vmaddr_TEXT; - if (isSplitKext) { - if (kxld_seg_is_text_exec_seg(seg)) { - my_link_addr = object->split_info.vmaddr_TEXT_EXEC; - } - else if (kxld_seg_is_data_seg(seg)) { - my_link_addr = object->split_info.vmaddr_DATA; - } - else if (kxld_seg_is_data_const_seg(seg)) { - my_link_addr = object->split_info.vmaddr_DATA_CONST; - } - else if (kxld_seg_is_llvm_cov_seg(seg)) { - my_link_addr = object->split_info.vmaddr_LLVM_COV; - } - else if (kxld_seg_is_linkedit_seg(seg)) { - my_link_addr = object->split_info.vmaddr_LINKEDIT; - } - } - rval = kxld_relocator_process_table_reloc(&object->relocator, - reloc, - seg, - my_link_addr); - } - require_noerr(rval, finish); - } - - /* Process local relocations */ - for (i = 0; i < object->locrelocs.nitems; ++i) { - reloc = kxld_array_get_item(&object->locrelocs, i); - - seg = get_seg_by_base_addr(object, reloc->address); - require_action(seg, finish, rval=KERN_FAILURE); - - if (isOldInterface) { - rval = kxld_relocator_process_table_reloc(&object->relocator, reloc, - seg, object->link_addr); - } - else { - kxld_addr_t my_link_addr = object->split_info.vmaddr_TEXT; - if (isSplitKext) { - if (kxld_seg_is_text_exec_seg(seg)) { - my_link_addr = object->split_info.vmaddr_TEXT_EXEC; - } - else if (kxld_seg_is_data_seg(seg)) { - my_link_addr = object->split_info.vmaddr_DATA; - } - else if (kxld_seg_is_data_const_seg(seg)) { - my_link_addr = object->split_info.vmaddr_DATA_CONST; - } - else if (kxld_seg_is_llvm_cov_seg(seg)) { - my_link_addr = object->split_info.vmaddr_LLVM_COV; - } - else if (kxld_seg_is_linkedit_seg(seg)) { - my_link_addr = object->split_info.vmaddr_LINKEDIT; - } - } - rval = kxld_relocator_process_table_reloc(&object->relocator, - reloc, - seg, - my_link_addr); - } - require_noerr(rval, finish); - } - - rval = KERN_SUCCESS; + kern_return_t rval = KERN_FAILURE; + KXLDReloc *reloc = NULL; + KXLDSeg *seg = NULL; + u_int i = 0; + + /* Process external relocations */ + for (i = 0; i < object->extrelocs.nitems; ++i) { + reloc = kxld_array_get_item(&object->extrelocs, i); + + seg = get_seg_by_base_addr(object, reloc->address); + require_action(seg, finish, rval = KERN_FAILURE); + + if (isOldInterface) { + rval = kxld_relocator_process_table_reloc(&object->relocator, reloc, + seg, object->link_addr); + } else { + kxld_addr_t my_link_addr = object->split_info.vmaddr_TEXT; + if (isSplitKext) { + if (kxld_seg_is_text_exec_seg(seg)) { + my_link_addr = object->split_info.vmaddr_TEXT_EXEC; + } else if (kxld_seg_is_data_seg(seg)) { + my_link_addr = object->split_info.vmaddr_DATA; + } else if (kxld_seg_is_data_const_seg(seg)) { + my_link_addr = object->split_info.vmaddr_DATA_CONST; + } else if (kxld_seg_is_llvm_cov_seg(seg)) { + my_link_addr = object->split_info.vmaddr_LLVM_COV; + } else if (kxld_seg_is_linkedit_seg(seg)) { + my_link_addr = object->split_info.vmaddr_LINKEDIT; + } + } + rval = kxld_relocator_process_table_reloc(&object->relocator, + reloc, + seg, + my_link_addr); + } + require_noerr(rval, finish); + } + + /* Process local relocations */ + for (i = 0; i < object->locrelocs.nitems; ++i) { + reloc = kxld_array_get_item(&object->locrelocs, i); + + seg = get_seg_by_base_addr(object, reloc->address); + require_action(seg, finish, rval = KERN_FAILURE); + + if (isOldInterface) { + rval = kxld_relocator_process_table_reloc(&object->relocator, reloc, + seg, object->link_addr); + } else { + kxld_addr_t my_link_addr = object->split_info.vmaddr_TEXT; + if (isSplitKext) { + if (kxld_seg_is_text_exec_seg(seg)) { + my_link_addr = object->split_info.vmaddr_TEXT_EXEC; + } else if (kxld_seg_is_data_seg(seg)) { + my_link_addr = object->split_info.vmaddr_DATA; + } else if (kxld_seg_is_data_const_seg(seg)) { + my_link_addr = object->split_info.vmaddr_DATA_CONST; + } else if (kxld_seg_is_llvm_cov_seg(seg)) { + my_link_addr = object->split_info.vmaddr_LLVM_COV; + } else if (kxld_seg_is_linkedit_seg(seg)) { + my_link_addr = object->split_info.vmaddr_LINKEDIT; + } + } + rval = kxld_relocator_process_table_reloc(&object->relocator, + reloc, + seg, + my_link_addr); + } + require_noerr(rval, finish); + } + + rval = KERN_SUCCESS; finish: - return rval; + return rval; } /******************************************************************************* @@ -2548,20 +2577,19 @@ finish: static void add_to_ptr(u_char *symptr, kxld_addr_t val, boolean_t is_32_bit) { - if (is_32_bit) { - uint32_t *ptr = (uint32_t *) ((void *) symptr); - - *ptr += (uint32_t) val; - } else { - uint64_t *ptr = (uint64_t *) ((void *) symptr); - - *ptr += (uint64_t) val; - } - + if (is_32_bit) { + uint32_t *ptr = (uint32_t *) ((void *) symptr); + + *ptr += (uint32_t) val; + } else { + uint64_t *ptr = (uint64_t *) ((void *) symptr); + + *ptr += (uint64_t) val; + } + #if SPLIT_KEXTS_DEBUG - kxld_show_ptr_value = FALSE; + kxld_show_ptr_value = FALSE; #endif - } #endif /* KXLD_USER_OR_BUNDLE */ @@ -2571,19 +2599,19 @@ add_to_ptr(u_char *symptr, kxld_addr_t val, boolean_t is_32_bit) static kern_return_t process_relocs_from_sections(KXLDObject *object) { - kern_return_t rval = KERN_FAILURE; - KXLDSect *sect = NULL; - u_int i = 0; + kern_return_t rval = KERN_FAILURE; + KXLDSect *sect = NULL; + u_int i = 0; - for (i = 0; i < object->sects.nitems; ++i) { - sect = kxld_array_get_item(&object->sects, i); - rval = kxld_sect_process_relocs(sect, &object->relocator); - require_noerr(rval, finish); - } + for (i = 0; i < object->sects.nitems; ++i) { + sect = kxld_array_get_item(&object->sects, i); + rval = kxld_sect_process_relocs(sect, &object->relocator); + require_noerr(rval, finish); + } - rval = KERN_SUCCESS; + rval = KERN_SUCCESS; finish: - return rval; + return rval; } #endif /* KXLD_USER_OR_OBJECT */ @@ -2592,109 +2620,106 @@ finish: static kern_return_t populate_kmod_info(KXLDObject *object) { - kern_return_t rval = KERN_FAILURE; - KXLDSect *kmodsect = NULL; - KXLDSym *kmodsym = NULL; - kmod_info_t *kmod_info = NULL; - u_long kmod_offset = 0; - u_long header_size; - u_long size; - - if (kxld_object_is_kernel(object)) { - rval = KERN_SUCCESS; - goto finish; - } - - kxld_object_get_vmsize(object, &header_size, &size); - - kmodsym = kxld_symtab_get_locally_defined_symbol_by_name(object->symtab, - KXLD_KMOD_INFO_SYMBOL); - require_action(kmodsym, finish, rval=KERN_FAILURE; - kxld_log(kKxldLogLinking, kKxldLogErr, kKxldLogNoKmodInfo)); - - kmodsect = kxld_array_get_item(&object->sects, kmodsym->sectnum); - - kmod_offset = (u_long) (kmodsym->base_addr - kmodsect->base_addr); - kmod_info = (kmod_info_t *) ((void *) (kmodsect->data + kmod_offset)); - - if (kxld_object_is_32_bit(object)) { - kmod_info_32_v1_t *kmod = (kmod_info_32_v1_t *) (kmod_info); - - if (isOldInterface) { - kmod->address = (uint32_t) object->link_addr; - } - else { - kmod->address = (uint32_t) object->split_info.vmaddr_TEXT; - } - - kmod->size = (uint32_t) size; - kmod->hdr_size = (uint32_t) header_size; + kern_return_t rval = KERN_FAILURE; + KXLDSect *kmodsect = NULL; + KXLDSym *kmodsym = NULL; + kmod_info_t *kmod_info = NULL; + u_long kmod_offset = 0; + u_long header_size; + u_long size; + + if (kxld_object_is_kernel(object)) { + rval = KERN_SUCCESS; + goto finish; + } + + kxld_object_get_vmsize(object, &header_size, &size); + + kmodsym = kxld_symtab_get_locally_defined_symbol_by_name(object->symtab, + KXLD_KMOD_INFO_SYMBOL); + require_action(kmodsym, finish, rval = KERN_FAILURE; + kxld_log(kKxldLogLinking, kKxldLogErr, kKxldLogNoKmodInfo)); + + kmodsect = kxld_array_get_item(&object->sects, kmodsym->sectnum); + + kmod_offset = (u_long) (kmodsym->base_addr - kmodsect->base_addr); + kmod_info = (kmod_info_t *) ((void *) (kmodsect->data + kmod_offset)); + + if (kxld_object_is_32_bit(object)) { + kmod_info_32_v1_t *kmod = (kmod_info_32_v1_t *) (kmod_info); + + if (isOldInterface) { + kmod->address = (uint32_t) object->link_addr; + } else { + kmod->address = (uint32_t) object->split_info.vmaddr_TEXT; + } + + kmod->size = (uint32_t) size; + kmod->hdr_size = (uint32_t) header_size; #if !KERNEL - if (kxld_object_target_needs_swap(object)) { - kmod->address = OSSwapInt32(kmod->address); - kmod->size = OSSwapInt32(kmod->size); - kmod->hdr_size = OSSwapInt32(kmod->hdr_size); - } + if (kxld_object_target_needs_swap(object)) { + kmod->address = OSSwapInt32(kmod->address); + kmod->size = OSSwapInt32(kmod->size); + kmod->hdr_size = OSSwapInt32(kmod->hdr_size); + } #endif /* !KERNEL */ - } else { - kmod_info_64_v1_t *kmod = (kmod_info_64_v1_t *) (kmod_info); - - if (isOldInterface) { - kmod->address = object->link_addr; - } - else { - kmod->address = object->split_info.vmaddr_TEXT; - } - - kmod->size = size; - kmod->hdr_size = header_size; + } else { + kmod_info_64_v1_t *kmod = (kmod_info_64_v1_t *) (kmod_info); + + if (isOldInterface) { + kmod->address = object->link_addr; + } else { + kmod->address = object->split_info.vmaddr_TEXT; + } + + kmod->size = size; + kmod->hdr_size = header_size; #if !KERNEL - if (kxld_object_target_needs_swap(object)) { - kmod->address = OSSwapInt64(kmod->address); - kmod->size = OSSwapInt64(kmod->size); - kmod->hdr_size = OSSwapInt64(kmod->hdr_size); - } + if (kxld_object_target_needs_swap(object)) { + kmod->address = OSSwapInt64(kmod->address); + kmod->size = OSSwapInt64(kmod->size); + kmod->hdr_size = OSSwapInt64(kmod->hdr_size); + } #endif /* !KERNEL */ - + #if SPLIT_KEXTS_DEBUG - { - kxld_log(kKxldLogLinking, kKxldLogErr, - " kmodsect %p kmod_info %p = kmodsect->data %p + kmod_offset %lu <%s>", - (void *) kmodsect, - (void *) kmod_info, - (void *) kmodsect->data, - kmod_offset, - __func__); - - kxld_log(kKxldLogLinking, kKxldLogErr, - " kmod_info data: address %p size %llu hdr_size %llu start_addr %p stop_addr %p <%s>", - (void *) kmod->address, - kmod->size, - kmod->hdr_size, - (void *) kmod->start_addr, - (void *) kmod->stop_addr, - __func__); - } + { + kxld_log(kKxldLogLinking, kKxldLogErr, + " kmodsect %p kmod_info %p = kmodsect->data %p + kmod_offset %lu <%s>", + (void *) kmodsect, + (void *) kmod_info, + (void *) kmodsect->data, + kmod_offset, + __func__); + + kxld_log(kKxldLogLinking, kKxldLogErr, + " kmod_info data: address %p size %llu hdr_size %llu start_addr %p stop_addr %p <%s>", + (void *) kmod->address, + kmod->size, + kmod->hdr_size, + (void *) kmod->start_addr, + (void *) kmod->stop_addr, + __func__); + } #endif + } - } - - rval = KERN_SUCCESS; + rval = KERN_SUCCESS; finish: - return rval; + return rval; } #if KXLD_PIC_KEXTS /******************************************************************************* - *******************************************************************************/ +*******************************************************************************/ static boolean_t target_supports_slideable_kexts(const KXLDObject *object) { - check(object); + check(object); - return (object->cputype != CPU_TYPE_I386 && object->include_kaslr_relocs); + return object->cputype != CPU_TYPE_I386 && object->include_kaslr_relocs; } #endif /* KXLD_PIC_KEXTS */