X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/316670eb35587141e969394ae8537d66b9211e80..HEAD:/libkern/kxld/kxld_kext.c diff --git a/libkern/kxld/kxld_kext.c b/libkern/kxld/kxld_kext.c index a9ef47798..eafc9d591 100644 --- a/libkern/kxld/kxld_kext.c +++ b/libkern/kxld/kxld_kext.c @@ -1,8 +1,8 @@ /* - * Copyright (c) 2008 Apple Inc. All rights reserved. + * Copyright (c) 2008, 2013 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 @@ -45,6 +45,7 @@ #include #include #include + #endif /* KERNEL */ #define DEBUG_ASSERT_COMPONENT_NAME_STRING "kxld" @@ -61,15 +62,17 @@ #include "kxld_util.h" #include "kxld_vtable.h" +extern boolean_t isSplitKext; + struct symtab_command; struct kxld_kext { - KXLDObject *kext; - KXLDObject *interface; - KXLDArray vtables; - KXLDDict vtable_index; - boolean_t vtables_created; - boolean_t vtable_index_created; + KXLDObject *kext; + KXLDObject *interface; + KXLDArray vtables; + KXLDDict vtable_index; + boolean_t vtables_created; + boolean_t vtable_index_created; }; /******************************************************************************* @@ -77,28 +80,28 @@ struct kxld_kext { *******************************************************************************/ static kern_return_t export_symbols_through_interface( - const KXLDObject *kext, const KXLDObject *interface, - KXLDDict *defined_symbols_by_name, - KXLDDict *defined_cxx_symbol_by_value, - KXLDDict *obsolete_symbols_by_name); + const KXLDObject *kext, const KXLDObject *interface, + KXLDDict *defined_symbols_by_name, + KXLDDict *defined_cxx_symbol_by_value, + KXLDDict *obsolete_symbols_by_name); static kern_return_t export_symbols(const KXLDObject *kext, - KXLDDict *defined_symbols_by_name, + KXLDDict *defined_symbols_by_name, KXLDDict *defined_cxx_symbols_by_value); static kern_return_t create_vtables(KXLDKext *kext, const KXLDDict *defined_symbols, const KXLDDict *defined_cxx_symbols); -static kern_return_t get_vtable_syms_from_smcp(KXLDKext *kext, - const KXLDDict *defined_symbols, KXLDSym *super_metaclass_ptr_sym, +static kern_return_t get_vtable_syms_from_smcp(KXLDKext *kext, + const KXLDDict *defined_symbols, KXLDSym *super_metaclass_ptr_sym, KXLDSym **vtable_sym_out, KXLDSym **meta_vtable_sym_out); -static kern_return_t resolve_symbols(KXLDKext *kext, +static kern_return_t resolve_symbols(KXLDKext *kext, const KXLDDict *defined_symbols, const KXLDDict *obsolete_symbols); static kern_return_t patch_vtables(KXLDKext *kext, KXLDDict *patched_vtables, const KXLDDict *defined_symbols); -static const KXLDSym *get_metaclass_symbol_from_super_meta_class_pointer_symbol( - KXLDKext *kext, KXLDSym *super_metaclass_pointer_sym); static kern_return_t create_vtable_index(KXLDKext *kext); +static const KXLDSym *get_metaclass_symbol_from_super_meta_class_pointer_symbol( + KXLDKext *kext, KXLDSym *super_metaclass_pointer_sym); static kern_return_t validate_symbols(KXLDKext *kext); @@ -107,32 +110,32 @@ static kern_return_t validate_symbols(KXLDKext *kext); size_t kxld_kext_sizeof(void) { - return sizeof(KXLDKext); + return sizeof(KXLDKext); } /******************************************************************************* *******************************************************************************/ kern_return_t -kxld_kext_init(KXLDKext *kext, KXLDObject *kext_object, +kxld_kext_init(KXLDKext *kext, KXLDObject *kext_object, KXLDObject *interface_object) { - kern_return_t rval = KERN_FAILURE; + kern_return_t rval = KERN_FAILURE; - check(kext); - check(kext_object); + check(kext); + check(kext_object); - kext->kext = kext_object; + kext->kext = kext_object; - if (interface_object) { - kext->interface = interface_object; + if (interface_object) { + kext->interface = interface_object; - rval = kxld_object_index_symbols_by_name(kext->kext); - require_noerr(rval, finish); - } - - rval = KERN_SUCCESS; + rval = kxld_object_index_symbols_by_name(kext->kext); + require_noerr(rval, finish); + } + + rval = KERN_SUCCESS; finish: - return rval; + return rval; } /******************************************************************************* @@ -140,71 +143,71 @@ finish: void kxld_kext_clear(KXLDKext *kext) { - KXLDVTable *vtable = NULL; - u_int i; - - check(kext); - - for (i = 0; i < kext->vtables.nitems; ++i) { - vtable = kxld_array_get_item(&kext->vtables, i); - kxld_vtable_clear(vtable); - } - kxld_array_reset(&kext->vtables); - kxld_dict_clear(&kext->vtable_index); - - kext->kext = NULL; - kext->interface = NULL; - kext->vtables_created = FALSE; - kext->vtable_index_created = FALSE; + KXLDVTable *vtable = NULL; + u_int i; + + check(kext); + + for (i = 0; i < kext->vtables.nitems; ++i) { + vtable = kxld_array_get_item(&kext->vtables, i); + kxld_vtable_clear(vtable); + } + kxld_array_reset(&kext->vtables); + kxld_dict_clear(&kext->vtable_index); + + kext->kext = NULL; + kext->interface = NULL; + kext->vtables_created = FALSE; + kext->vtable_index_created = FALSE; } /******************************************************************************* *******************************************************************************/ -void +void kxld_kext_deinit(KXLDKext *kext) { - KXLDVTable *vtable = NULL; - u_int i; + KXLDVTable *vtable = NULL; + u_int i; - check(kext); + check(kext); - for (i = 0; i < kext->vtables.maxitems; ++i) { - vtable = kxld_array_get_slot(&kext->vtables, i); - kxld_vtable_deinit(vtable); - } - kxld_array_deinit(&kext->vtables); - kxld_dict_deinit(&kext->vtable_index); + for (i = 0; i < kext->vtables.maxitems; ++i) { + vtable = kxld_array_get_slot(&kext->vtables, i); + kxld_vtable_deinit(vtable); + } + kxld_array_deinit(&kext->vtables); + kxld_dict_deinit(&kext->vtable_index); - bzero(kext, sizeof(*kext)); + bzero(kext, sizeof(*kext)); } /******************************************************************************* *******************************************************************************/ -kern_return_t -kxld_kext_export_symbols(const KXLDKext *kext, +kern_return_t +kxld_kext_export_symbols(const KXLDKext *kext, KXLDDict *defined_symbols_by_name, KXLDDict *obsolete_symbols_by_name, KXLDDict *defined_cxx_symbols_by_value) { - kern_return_t rval = KERN_FAILURE; - - check(kext); - - if (kext->interface) { - rval = export_symbols_through_interface(kext->kext, kext->interface, - defined_symbols_by_name, obsolete_symbols_by_name, - defined_cxx_symbols_by_value); - require_noerr(rval, finish); - } else { - rval = export_symbols(kext->kext, defined_symbols_by_name, - defined_cxx_symbols_by_value); - require_noerr(rval, finish); - } - - rval = KERN_SUCCESS; + kern_return_t rval = KERN_FAILURE; + + check(kext); + + if (kext->interface) { + rval = export_symbols_through_interface(kext->kext, kext->interface, + defined_symbols_by_name, obsolete_symbols_by_name, + defined_cxx_symbols_by_value); + require_noerr(rval, finish); + } else { + rval = export_symbols(kext->kext, defined_symbols_by_name, + defined_cxx_symbols_by_value); + require_noerr(rval, finish); + } + + rval = KERN_SUCCESS; finish: - return rval; + return rval; } /******************************************************************************* @@ -214,84 +217,84 @@ export_symbols_through_interface(const KXLDObject *kext, const KXLDObject *interface, KXLDDict *defined_symbols_by_name, KXLDDict *obsolete_symbols_by_name, KXLDDict *defined_cxx_symbols_by_value) { - kern_return_t rval = KERN_FAILURE; - KXLDSymtabIterator iter; - const KXLDSymtab *kext_symtab = NULL; - const KXLDSymtab *interface_symtab = NULL; - KXLDSym *kext_sym = NULL; - const KXLDSym *interface_sym = NULL; - - check(kext); - check(interface); - - kext_symtab = kxld_object_get_symtab(kext); - interface_symtab = kxld_object_get_symtab(interface); - - if (defined_symbols_by_name) { - /* Add exported symbols */ - (void) kxld_symtab_iterator_init(&iter, interface_symtab, - kxld_sym_is_undefined, FALSE); - while ((interface_sym = kxld_symtab_iterator_get_next(&iter))) { - kext_sym = kxld_symtab_get_locally_defined_symbol_by_name(kext_symtab, - interface_sym->name); - if (!kext_sym) { - kxld_log(kKxldLogLinking, kKxldLogWarn, - "In interface %s of %s, couldn't find symbol %s\n", - kxld_object_get_name(interface), kxld_object_get_name(kext), - interface_sym->name); - continue; - } - - rval = kxld_dict_insert(defined_symbols_by_name, - kext_sym->name, kext_sym); - require_noerr(rval, finish); - } - - /* Add indirect symbols */ - (void) kxld_symtab_iterator_init(&iter, interface_symtab, - kxld_sym_is_indirect, FALSE); - while ((interface_sym = kxld_symtab_iterator_get_next(&iter))) { - kext_sym = kxld_symtab_get_locally_defined_symbol_by_name(kext_symtab, - interface_sym->alias); - if (!kext_sym) { - kxld_log(kKxldLogLinking, kKxldLogWarn, - "In interface %s of %s, couldn't find indirect symbol %s (%s)\n", - kxld_object_get_name(interface), kxld_object_get_name(kext), - interface_sym->alias, interface_sym->name); - continue; - } - - rval = kxld_dict_insert(defined_symbols_by_name, - interface_sym->name, kext_sym); - require_noerr(rval, finish); - } - } - - /* Add obsolete symbols */ - if (obsolete_symbols_by_name) { - (void) kxld_symtab_iterator_init(&iter, interface_symtab, - kxld_sym_is_obsolete, FALSE); - while ((kext_sym = kxld_symtab_iterator_get_next(&iter))) { - rval = kxld_dict_insert(obsolete_symbols_by_name, - kext_sym->name, kext_sym); - require_noerr(rval, finish); - } - } - - /* Add C++ symbols */ - if (defined_cxx_symbols_by_value) { - (void) kxld_symtab_iterator_init(&iter, kext_symtab, - kxld_sym_is_cxx, FALSE); - while ((kext_sym = kxld_symtab_iterator_get_next(&iter))) { - rval = kxld_dict_insert(defined_cxx_symbols_by_value, - &kext_sym->link_addr, kext_sym); - require_noerr(rval, finish); - } - } - - rval = KERN_SUCCESS; + kern_return_t rval = KERN_FAILURE; + KXLDSymtabIterator iter; + const KXLDSymtab *kext_symtab = NULL; + const KXLDSymtab *interface_symtab = NULL; + KXLDSym *kext_sym = NULL; + const KXLDSym *interface_sym = NULL; + + check(kext); + check(interface); + + kext_symtab = kxld_object_get_symtab(kext); + interface_symtab = kxld_object_get_symtab(interface); + + if (defined_symbols_by_name) { + /* Add exported symbols */ + (void) kxld_symtab_iterator_init(&iter, interface_symtab, + kxld_sym_is_undefined, FALSE); + while ((interface_sym = kxld_symtab_iterator_get_next(&iter))) { + kext_sym = kxld_symtab_get_locally_defined_symbol_by_name(kext_symtab, + interface_sym->name); + if (!kext_sym) { + kxld_log(kKxldLogLinking, kKxldLogWarn, + "In interface %s of %s, couldn't find symbol %s\n", + kxld_object_get_name(interface), kxld_object_get_name(kext), + interface_sym->name); + continue; + } + + rval = kxld_dict_insert(defined_symbols_by_name, + kext_sym->name, kext_sym); + require_noerr(rval, finish); + } + + /* Add indirect symbols */ + (void) kxld_symtab_iterator_init(&iter, interface_symtab, + kxld_sym_is_indirect, FALSE); + while ((interface_sym = kxld_symtab_iterator_get_next(&iter))) { + kext_sym = kxld_symtab_get_locally_defined_symbol_by_name(kext_symtab, + interface_sym->alias); + if (!kext_sym) { + kxld_log(kKxldLogLinking, kKxldLogWarn, + "In interface %s of %s, couldn't find indirect symbol %s (%s)\n", + kxld_object_get_name(interface), kxld_object_get_name(kext), + interface_sym->alias, interface_sym->name); + continue; + } + + rval = kxld_dict_insert(defined_symbols_by_name, + interface_sym->name, kext_sym); + require_noerr(rval, finish); + } + } + + /* Add obsolete symbols */ + if (obsolete_symbols_by_name) { + (void) kxld_symtab_iterator_init(&iter, interface_symtab, + kxld_sym_is_obsolete, FALSE); + while ((kext_sym = kxld_symtab_iterator_get_next(&iter))) { + rval = kxld_dict_insert(obsolete_symbols_by_name, + kext_sym->name, kext_sym); + require_noerr(rval, finish); + } + } + + /* Add C++ symbols */ + if (defined_cxx_symbols_by_value) { + (void) kxld_symtab_iterator_init(&iter, kext_symtab, + kxld_sym_is_cxx, FALSE); + while ((kext_sym = kxld_symtab_iterator_get_next(&iter))) { + rval = kxld_dict_insert(defined_cxx_symbols_by_value, + &kext_sym->link_addr, kext_sym); + require_noerr(rval, finish); + } + } + + rval = KERN_SUCCESS; finish: - return rval; + return rval; } /******************************************************************************* @@ -300,147 +303,163 @@ kern_return_t export_symbols(const KXLDObject *kext, KXLDDict *defined_symbols_by_name, KXLDDict *defined_cxx_symbols_by_value) { - kern_return_t rval = KERN_FAILURE; - KXLDSymtabIterator iter; - KXLDSym *sym = NULL; - - (void) kxld_symtab_iterator_init(&iter, kxld_object_get_symtab(kext), - kxld_sym_is_exported, FALSE); - while ((sym = kxld_symtab_iterator_get_next(&iter))) { - if (defined_symbols_by_name) { - rval = kxld_dict_insert(defined_symbols_by_name, sym->name, sym); - require_noerr(rval, finish); - } - - if (kxld_sym_is_cxx(sym) && defined_cxx_symbols_by_value) { - rval = kxld_dict_insert(defined_cxx_symbols_by_value, - &sym->link_addr, sym); - require_noerr(rval, finish); - } - } - - rval = KERN_SUCCESS; + kern_return_t rval = KERN_FAILURE; + KXLDSymtabIterator iter; + KXLDSym *sym = NULL; + + (void) kxld_symtab_iterator_init(&iter, kxld_object_get_symtab(kext), + kxld_sym_is_exported, FALSE); + while ((sym = kxld_symtab_iterator_get_next(&iter))) { + if (defined_symbols_by_name) { + rval = kxld_dict_insert(defined_symbols_by_name, sym->name, sym); + require_noerr(rval, finish); + } + + if (kxld_sym_is_cxx(sym) && defined_cxx_symbols_by_value) { + rval = kxld_dict_insert(defined_cxx_symbols_by_value, + &sym->link_addr, sym); + require_noerr(rval, finish); + } + } + + rval = KERN_SUCCESS; finish: - return rval; + return rval; } /******************************************************************************* *******************************************************************************/ -kern_return_t +kern_return_t kxld_kext_export_vtables(KXLDKext *kext, const KXLDDict *defined_cxx_symbols, const KXLDDict *defined_symbols, KXLDDict *vtables) { - kern_return_t rval = KERN_FAILURE; - KXLDVTable *vtable = NULL; - u_int i = 0; - - check(kext); - check(defined_symbols); - check(defined_cxx_symbols); - check(vtables); - - rval = create_vtables(kext, defined_cxx_symbols, defined_symbols); - require_noerr(rval, finish); - - for (i = 0; i < kext->vtables.nitems; ++i) { - vtable = kxld_array_get_item(&kext->vtables, i); - - rval = kxld_dict_insert(vtables, vtable->name, vtable); - require_noerr(rval, finish); - } - - rval = KERN_SUCCESS; + kern_return_t rval = KERN_FAILURE; + KXLDVTable *vtable = NULL; + u_int i = 0; + + check(kext); + check(defined_symbols); + check(defined_cxx_symbols); + check(vtables); + + rval = create_vtables(kext, defined_cxx_symbols, defined_symbols); + require_noerr(rval, finish); + + for (i = 0; i < kext->vtables.nitems; ++i) { + vtable = kxld_array_get_item(&kext->vtables, i); + + rval = kxld_dict_insert(vtables, vtable->name, vtable); + require_noerr(rval, finish); + } + + rval = KERN_SUCCESS; finish: - return rval; + return rval; +} + +/******************************************************************************* +*******************************************************************************/ +void +kxld_kext_get_vmsize_for_seg_by_name(const KXLDKext *kext, + const char *segname, + u_long *vmsize) +{ + (void) kxld_object_get_vmsize_for_seg_by_name(kext->kext, segname, vmsize); } /******************************************************************************* *******************************************************************************/ -void -kxld_kext_get_vmsize(const KXLDKext *kext, +void +kxld_kext_get_vmsize(const KXLDKext *kext, u_long *header_size, u_long *vmsize) { - (void) kxld_object_get_vmsize(kext->kext, header_size, vmsize); + (void) kxld_object_get_vmsize(kext->kext, header_size, vmsize); } /******************************************************************************* - *******************************************************************************/ -void +*******************************************************************************/ +void kxld_kext_set_linked_object_size(KXLDKext *kext, u_long vmsize) { - (void) kxld_object_set_linked_object_size(kext->kext, vmsize); + (void) kxld_object_set_linked_object_size(kext->kext, vmsize); } - /******************************************************************************* *******************************************************************************/ -kern_return_t -kxld_kext_export_linked_object(const KXLDKext *kext, - u_char *linked_object, kxld_addr_t *kmod_info) +kern_return_t +kxld_kext_export_linked_object(const KXLDKext *kext, + void *linked_object, + kxld_addr_t *kmod_info) { - kern_return_t rval = KERN_FAILURE; - const KXLDSym *kmodsym = NULL; + kern_return_t rval = KERN_FAILURE; + const KXLDSym *kmodsym = NULL; + + kmodsym = kxld_symtab_get_locally_defined_symbol_by_name( + kxld_object_get_symtab(kext->kext), KXLD_KMOD_INFO_SYMBOL); + + require_action(kmodsym, finish, rval = KERN_FAILURE; + kxld_log(kKxldLogLinking, kKxldLogErr, kKxldLogNoKmodInfo)); - kmodsym = kxld_symtab_get_locally_defined_symbol_by_name( - kxld_object_get_symtab(kext->kext), KXLD_KMOD_INFO_SYMBOL); - require_action(kmodsym, finish, rval=KERN_FAILURE; - kxld_log(kKxldLogLinking, kKxldLogErr, kKxldLogNoKmodInfo)); - - *kmod_info = kmodsym->link_addr; + *kmod_info = kmodsym->link_addr; - rval = kxld_object_export_linked_object(kext->kext, linked_object); + rval = kxld_object_export_linked_object(kext->kext, linked_object); finish: - return rval; + return rval; } /******************************************************************************* *******************************************************************************/ kern_return_t -kxld_kext_relocate(KXLDKext *kext, kxld_addr_t link_address, - KXLDDict *patched_vtables, const KXLDDict *defined_symbols, - const KXLDDict *obsolete_symbols, const KXLDDict *defined_cxx_symbols) +kxld_kext_relocate(KXLDKext *kext, + kxld_addr_t link_address, + KXLDDict *patched_vtables, + const KXLDDict *defined_symbols, + const KXLDDict *obsolete_symbols, + const KXLDDict *defined_cxx_symbols) { - kern_return_t rval = KERN_FAILURE; + kern_return_t rval = KERN_FAILURE; - check(kext); - check(patched_vtables); - check(defined_symbols); - check(obsolete_symbols); + check(kext); + check(patched_vtables); + check(defined_symbols); + check(obsolete_symbols); - /* Kexts that are being relocated need symbols indexed by value for vtable - * creation and patching. Note that we don't need to index by value for - * dependencies that have already been linked because their symbols are - * already in the global cxx value table. It's important to index the - * symbols by value before we relocate the symbols because the vtable - * entries will still have unrelocated values. - */ - rval = kxld_object_index_cxx_symbols_by_value(kext->kext); - require_noerr(rval, finish); + /* Kexts that are being relocated need symbols indexed by value for vtable + * creation and patching. Note that we don't need to index by value for + * dependencies that have already been linked because their symbols are + * already in the global cxx value table. It's important to index the + * symbols by value before we relocate the symbols because the vtable + * entries will still have unrelocated values. + */ + rval = kxld_object_index_cxx_symbols_by_value(kext->kext); + require_noerr(rval, finish); - rval = kxld_object_index_symbols_by_name(kext->kext); - require_noerr(rval, finish); + rval = kxld_object_index_symbols_by_name(kext->kext); + require_noerr(rval, finish); - rval = kxld_object_relocate(kext->kext, link_address); - require_noerr(rval, finish); + rval = kxld_object_relocate(kext->kext, link_address); + require_noerr(rval, finish); - rval = resolve_symbols(kext, defined_symbols, obsolete_symbols); - require_noerr(rval, finish); + rval = resolve_symbols(kext, defined_symbols, obsolete_symbols); + require_noerr(rval, finish); - rval = create_vtables(kext, defined_cxx_symbols, /* defined_symbols */ NULL); - require_noerr(rval, finish); + rval = create_vtables(kext, defined_cxx_symbols, /* defined_symbols */ NULL); + require_noerr(rval, finish); - rval = patch_vtables(kext, patched_vtables, defined_symbols); - require_noerr(rval, finish); - - rval = validate_symbols(kext); - require_noerr(rval, finish); + if (isSplitKext == FALSE) { + rval = patch_vtables(kext, patched_vtables, defined_symbols); + require_noerr(rval, finish); + } - rval = kxld_object_process_relocations(kext->kext, patched_vtables); - require_noerr(rval, finish); + rval = validate_symbols(kext); + require_noerr(rval, finish); - rval = KERN_SUCCESS; + rval = kxld_object_process_relocations(kext->kext, patched_vtables); + require_noerr(rval, finish); + + rval = KERN_SUCCESS; finish: - return rval; + return rval; } /******************************************************************************* @@ -453,317 +472,317 @@ finish: * linked kexts export their symbols into the global symbol table that is used * for symbol resolution, so we can look there for vtable symbols without * having to index their local symbol table separately. -* +* * Unlinked kexts haven't yet had their symbols exported into the global table, * so we have to index their local symbol table separately. *******************************************************************************/ -static kern_return_t +static kern_return_t create_vtables(KXLDKext *kext, const KXLDDict *defined_cxx_symbols, const KXLDDict *defined_symbols) { - kern_return_t rval = KERN_FAILURE; - const KXLDSymtab *symtab = NULL; - KXLDSymtabIterator iter; - KXLDSym *sym = NULL; - KXLDSym *vtable_sym = NULL; - KXLDSym *meta_vtable_sym = NULL; - KXLDVTable *vtable = NULL; - KXLDVTable *meta_vtable = NULL; - u_int i = 0; - u_int nvtables = 0; - - if (kext->vtables_created) { - rval = KERN_SUCCESS; - goto finish; - } - - symtab = kxld_object_get_symtab(kext->kext); - - if (kxld_object_is_linked(kext->kext)) { - /* Create a vtable object for every vtable symbol */ - kxld_symtab_iterator_init(&iter, symtab, kxld_sym_is_vtable, FALSE); - nvtables = kxld_symtab_iterator_get_num_remaining(&iter); - } else { - /* We walk over the super metaclass pointer symbols because classes - * with them are the only ones that need patching. Then we double the - * number of vtables we're expecting, because every pointer will have a - * class vtable and a MetaClass vtable. - */ - kxld_symtab_iterator_init(&iter, symtab, - kxld_sym_is_super_metaclass_pointer, FALSE); - nvtables = kxld_symtab_iterator_get_num_remaining(&iter) * 2; - } - - rval = kxld_array_init(&kext->vtables, sizeof(KXLDVTable), nvtables); - require_noerr(rval, finish); - - while ((sym = kxld_symtab_iterator_get_next(&iter))) { - if (kxld_object_is_linked(kext->kext)) { - vtable_sym = sym; - meta_vtable_sym = NULL; - meta_vtable = NULL; - } else { - rval = get_vtable_syms_from_smcp(kext, defined_symbols, sym, - &vtable_sym, &meta_vtable_sym); - require_noerr(rval, finish); - } - - vtable = kxld_array_get_item(&kext->vtables, i++); - rval = kxld_vtable_init(vtable, vtable_sym, kext->kext, - defined_cxx_symbols); - require_noerr(rval, finish); - - /* meta_vtable_sym will be null when we don't support strict - * patching and can't find the metaclass vtable. If that's the - * case, we just reduce the expect number of vtables by 1. - */ - if (!kxld_object_is_linked(kext->kext)) { - if (meta_vtable_sym) { - meta_vtable = kxld_array_get_item(&kext->vtables, i++); - rval = kxld_vtable_init(meta_vtable, meta_vtable_sym, - kext->kext, defined_cxx_symbols); - require_noerr(rval, finish); - } else { - kxld_array_resize(&kext->vtables, --nvtables); - meta_vtable = NULL; - } - } - } - require_action(i == kext->vtables.nitems, finish, - rval=KERN_FAILURE); - - kext->vtables_created = TRUE; - rval = KERN_SUCCESS; + kern_return_t rval = KERN_FAILURE; + const KXLDSymtab *symtab = NULL; + KXLDSymtabIterator iter; + KXLDSym *sym = NULL; + KXLDSym *vtable_sym = NULL; + KXLDSym *meta_vtable_sym = NULL; + KXLDVTable *vtable = NULL; + KXLDVTable *meta_vtable = NULL; + u_int i = 0; + u_int nvtables = 0; + + if (kext->vtables_created) { + rval = KERN_SUCCESS; + goto finish; + } + + symtab = kxld_object_get_symtab(kext->kext); + + if (kxld_object_is_linked(kext->kext)) { + /* Create a vtable object for every vtable symbol */ + kxld_symtab_iterator_init(&iter, symtab, kxld_sym_is_vtable, FALSE); + nvtables = kxld_symtab_iterator_get_num_remaining(&iter); + } else { + /* We walk over the super metaclass pointer symbols because classes + * with them are the only ones that need patching. Then we double the + * number of vtables we're expecting, because every pointer will have a + * class vtable and a MetaClass vtable. + */ + kxld_symtab_iterator_init(&iter, symtab, + kxld_sym_is_super_metaclass_pointer, FALSE); + nvtables = kxld_symtab_iterator_get_num_remaining(&iter) * 2; + } + + rval = kxld_array_init(&kext->vtables, sizeof(KXLDVTable), nvtables); + require_noerr(rval, finish); + + while ((sym = kxld_symtab_iterator_get_next(&iter))) { + if (kxld_object_is_linked(kext->kext)) { + vtable_sym = sym; + meta_vtable_sym = NULL; + meta_vtable = NULL; + } else { + rval = get_vtable_syms_from_smcp(kext, defined_symbols, sym, + &vtable_sym, &meta_vtable_sym); + require_noerr(rval, finish); + } + + vtable = kxld_array_get_item(&kext->vtables, i++); + rval = kxld_vtable_init(vtable, vtable_sym, kext->kext, + defined_cxx_symbols); + require_noerr(rval, finish); + + /* meta_vtable_sym will be null when we don't support strict + * patching and can't find the metaclass vtable. If that's the + * case, we just reduce the expect number of vtables by 1. + */ + if (!kxld_object_is_linked(kext->kext)) { + if (meta_vtable_sym) { + meta_vtable = kxld_array_get_item(&kext->vtables, i++); + rval = kxld_vtable_init(meta_vtable, meta_vtable_sym, + kext->kext, defined_cxx_symbols); + require_noerr(rval, finish); + } else { + kxld_array_resize(&kext->vtables, --nvtables); + meta_vtable = NULL; + } + } + } + require_action(i == kext->vtables.nitems, finish, + rval = KERN_FAILURE); + + kext->vtables_created = TRUE; + rval = KERN_SUCCESS; finish: - return rval; + return rval; } /******************************************************************************* *******************************************************************************/ static kern_return_t get_vtable_syms_from_smcp(KXLDKext *kext, const KXLDDict *defined_symbols, - KXLDSym *super_metaclass_ptr_sym, KXLDSym **vtable_sym_out, + KXLDSym *super_metaclass_ptr_sym, KXLDSym **vtable_sym_out, KXLDSym **meta_vtable_sym_out) { - kern_return_t rval = KERN_FAILURE; - const KXLDSymtab *symtab = NULL; - KXLDSym *vtable_sym = NULL; - KXLDSym *meta_vtable_sym = NULL; - char class_name[KXLD_MAX_NAME_LEN]; - char vtable_name[KXLD_MAX_NAME_LEN]; - char meta_vtable_name[KXLD_MAX_NAME_LEN]; - char *demangled_name1 = NULL; - char *demangled_name2 = NULL; - size_t demangled_length1 = 0; - size_t demangled_length2 = 0; - - check(kext); - check(vtable_sym_out); - check(meta_vtable_sym_out); - - require(!kxld_object_is_kernel(kext->kext), finish); - - symtab = kxld_object_get_symtab(kext->kext); - - /* Get the class name from the smc pointer */ - rval = kxld_sym_get_class_name_from_super_metaclass_pointer( - super_metaclass_ptr_sym, class_name, sizeof(class_name)); - require_noerr(rval, finish); - - /* Get the vtable name from the class name */ - rval = kxld_sym_get_vtable_name_from_class_name(class_name, - vtable_name, sizeof(vtable_name)); - require_noerr(rval, finish); - - /* Get the vtable symbol */ - if (defined_symbols) { - vtable_sym = kxld_dict_find(defined_symbols, vtable_name); - } else { - vtable_sym = kxld_symtab_get_locally_defined_symbol_by_name(symtab, - vtable_name); - } - require_action(vtable_sym, finish, rval=KERN_FAILURE; - kxld_log(kKxldLogPatching, kKxldLogErr, kKxldLogMissingVtable, - vtable_name, class_name)); - - /* Get the meta vtable name from the class name */ - rval = kxld_sym_get_meta_vtable_name_from_class_name(class_name, - meta_vtable_name, sizeof(meta_vtable_name)); - require_noerr(rval, finish); - - /* Get the meta vtable symbol */ - if (defined_symbols) { - meta_vtable_sym = kxld_dict_find(defined_symbols, meta_vtable_name); - } else { - meta_vtable_sym = kxld_symtab_get_locally_defined_symbol_by_name(symtab, - meta_vtable_name); - } - if (!meta_vtable_sym) { - if (kxld_object_target_supports_strict_patching(kext->kext)) { - kxld_log(kKxldLogPatching, kKxldLogErr, - kKxldLogMissingVtable, - meta_vtable_name, class_name); - rval = KERN_FAILURE; - goto finish; - } else { - kxld_log(kKxldLogPatching, kKxldLogErr, - "Warning: " kKxldLogMissingVtable, - kxld_demangle(meta_vtable_name, &demangled_name1, - &demangled_length1), - kxld_demangle(class_name, &demangled_name2, - &demangled_length2)); - } - } - - *vtable_sym_out = vtable_sym; - *meta_vtable_sym_out = meta_vtable_sym; - rval = KERN_SUCCESS; + kern_return_t rval = KERN_FAILURE; + const KXLDSymtab *symtab = NULL; + KXLDSym *vtable_sym = NULL; + KXLDSym *meta_vtable_sym = NULL; + char class_name[KXLD_MAX_NAME_LEN]; + char vtable_name[KXLD_MAX_NAME_LEN]; + char meta_vtable_name[KXLD_MAX_NAME_LEN]; + char *demangled_name1 = NULL; + char *demangled_name2 = NULL; + size_t demangled_length1 = 0; + size_t demangled_length2 = 0; + + check(kext); + check(vtable_sym_out); + check(meta_vtable_sym_out); + + require(!kxld_object_is_kernel(kext->kext), finish); + + symtab = kxld_object_get_symtab(kext->kext); + + /* Get the class name from the smc pointer */ + rval = kxld_sym_get_class_name_from_super_metaclass_pointer( + super_metaclass_ptr_sym, class_name, sizeof(class_name)); + require_noerr(rval, finish); + + /* Get the vtable name from the class name */ + rval = kxld_sym_get_vtable_name_from_class_name(class_name, + vtable_name, sizeof(vtable_name)); + require_noerr(rval, finish); + + /* Get the vtable symbol */ + if (defined_symbols) { + vtable_sym = kxld_dict_find(defined_symbols, vtable_name); + } else { + vtable_sym = kxld_symtab_get_locally_defined_symbol_by_name(symtab, + vtable_name); + } + require_action(vtable_sym, finish, rval = KERN_FAILURE; + kxld_log(kKxldLogPatching, kKxldLogErr, kKxldLogMissingVtable, + vtable_name, class_name)); + + /* Get the meta vtable name from the class name */ + rval = kxld_sym_get_meta_vtable_name_from_class_name(class_name, + meta_vtable_name, sizeof(meta_vtable_name)); + require_noerr(rval, finish); + + /* Get the meta vtable symbol */ + if (defined_symbols) { + meta_vtable_sym = kxld_dict_find(defined_symbols, meta_vtable_name); + } else { + meta_vtable_sym = kxld_symtab_get_locally_defined_symbol_by_name(symtab, + meta_vtable_name); + } + if (!meta_vtable_sym) { + if (kxld_object_target_supports_strict_patching(kext->kext)) { + kxld_log(kKxldLogPatching, kKxldLogErr, + kKxldLogMissingVtable, + meta_vtable_name, class_name); + rval = KERN_FAILURE; + goto finish; + } else { + kxld_log(kKxldLogPatching, kKxldLogErr, + "Warning: " kKxldLogMissingVtable, + kxld_demangle(meta_vtable_name, &demangled_name1, + &demangled_length1), + kxld_demangle(class_name, &demangled_name2, + &demangled_length2)); + } + } + + *vtable_sym_out = vtable_sym; + *meta_vtable_sym_out = meta_vtable_sym; + rval = KERN_SUCCESS; finish: - if (demangled_name1) kxld_free(demangled_name1, demangled_length1); - if (demangled_name2) kxld_free(demangled_name2, demangled_length2); - - return rval; + if (demangled_name1) { + kxld_free(demangled_name1, demangled_length1); + } + if (demangled_name2) { + kxld_free(demangled_name2, demangled_length2); + } + + return rval; } /******************************************************************************* *******************************************************************************/ static kern_return_t -resolve_symbols(KXLDKext *kext, const KXLDDict *defined_symbols, +resolve_symbols(KXLDKext *kext, const KXLDDict *defined_symbols, const KXLDDict *obsolete_symbols) { - kern_return_t rval = KERN_FAILURE; - const KXLDSymtab *symtab = NULL; - KXLDSymtabIterator iter; - KXLDSym *sym = NULL; - KXLDSym *defined_sym = NULL; - const char *name = NULL; - boolean_t tests_for_weak = FALSE; - boolean_t error = FALSE; - char *demangled_name = NULL; - size_t demangled_length = 0; - - check(kext->kext); - check(defined_symbols); - check(obsolete_symbols); - - symtab = kxld_object_get_symtab(kext->kext); - - /* Check if the kext tests for weak symbols */ - sym = kxld_symtab_get_symbol_by_name(symtab, KXLD_WEAK_TEST_SYMBOL); - tests_for_weak = (sym != NULL); - - /* Check for duplicate symbols */ - kxld_symtab_iterator_init(&iter, symtab, kxld_sym_is_exported, FALSE); - while ((sym = kxld_symtab_iterator_get_next(&iter))) { - defined_sym = kxld_dict_find(defined_symbols, sym->name); - if (defined_sym) { - /* Not a problem if the symbols have the same address */ - if (defined_sym->link_addr == sym->link_addr) { - continue; - } - - if (!error) { - error = TRUE; - kxld_log(kKxldLogLinking, kKxldLogErr, - "The following symbols were defined more than once:"); - } - - kxld_log(kKxldLogLinking, kKxldLogErr, "\t%s: %p - %p", - kxld_demangle(sym->name, &demangled_name, &demangled_length), - (void *) (uintptr_t) sym->link_addr, - (void *) (uintptr_t) defined_sym->link_addr); - } - } - require_noerr_action(error, finish, rval=KERN_FAILURE); - - /* Resolve undefined and indirect symbols */ - - /* Iterate over all unresolved symbols */ - kxld_symtab_iterator_init(&iter, symtab, - kxld_sym_is_unresolved, FALSE); - while ((sym = kxld_symtab_iterator_get_next(&iter))) { - - /* Common symbols are not supported */ - if (kxld_sym_is_common(sym)) { - - if (!error) { - error = TRUE; - if (kxld_object_target_supports_common_symbols(kext->kext)) { - kxld_log(kKxldLogLinking, kKxldLogErr, - "The following common symbols were not resolved:"); - } else { - kxld_log(kKxldLogLinking, kKxldLogErr, - "Common symbols are not supported in kernel extensions. " - "Use -fno-common to build your kext. " - "The following are common symbols:"); - } - } - kxld_log(kKxldLogLinking, kKxldLogErr, "\t%s", - kxld_demangle(sym->name, &demangled_name, &demangled_length)); - - } else { - - /* Find the address of the defined symbol */ - if (kxld_sym_is_undefined(sym)) { - name = sym->name; - } else { - name = sym->alias; - } - defined_sym = kxld_dict_find(defined_symbols, name); - - /* Resolve the symbol. If a definition cannot be found, then: - * 1) Psuedokexts log a warning and proceed - * 2) Actual kexts delay the error until validation in case vtable - * patching replaces the undefined symbol. - */ - - if (defined_sym) { - - rval = kxld_sym_resolve(sym, defined_sym->link_addr); - require_noerr(rval, finish); - - if (obsolete_symbols && kxld_dict_find(obsolete_symbols, name)) { - kxld_log(kKxldLogLinking, kKxldLogWarn, - "This kext uses obsolete symbol %s.", - kxld_demangle(name, &demangled_name, &demangled_length)); - } - - } else if (kxld_sym_is_weak(sym)) { - kxld_addr_t addr = 0; - - /* Make sure that the kext has referenced gOSKextUnresolved. - */ - require_action(tests_for_weak, finish, - rval=KERN_FAILURE; - kxld_log(kKxldLogLinking, kKxldLogErr, - "This kext has weak references but does not test for " - "them. Test for weak references with " - "OSKextIsSymbolResolved().")); + kern_return_t rval = KERN_FAILURE; + const KXLDSymtab *symtab = NULL; + KXLDSymtabIterator iter; + KXLDSym *sym = NULL; + KXLDSym *defined_sym = NULL; + const char *name = NULL; + boolean_t tests_for_weak = FALSE; + boolean_t error = FALSE; + char *demangled_name = NULL; + size_t demangled_length = 0; + + check(kext->kext); + check(defined_symbols); + check(obsolete_symbols); + + symtab = kxld_object_get_symtab(kext->kext); + + /* Check if the kext tests for weak symbols */ + sym = kxld_symtab_get_symbol_by_name(symtab, KXLD_WEAK_TEST_SYMBOL); + tests_for_weak = (sym != NULL); + + /* Check for duplicate symbols */ + kxld_symtab_iterator_init(&iter, symtab, kxld_sym_is_exported, FALSE); + while ((sym = kxld_symtab_iterator_get_next(&iter))) { + defined_sym = kxld_dict_find(defined_symbols, sym->name); + if (defined_sym) { + /* Not a problem if the symbols have the same address */ + if (defined_sym->link_addr == sym->link_addr) { + continue; + } + + if (!error) { + error = TRUE; + kxld_log(kKxldLogLinking, kKxldLogErr, + "The following symbols were defined more than once:"); + } + + kxld_log(kKxldLogLinking, kKxldLogErr, "\t%s: %p - %p", + kxld_demangle(sym->name, &demangled_name, &demangled_length), + (void *) (uintptr_t) sym->link_addr, + (void *) (uintptr_t) defined_sym->link_addr); + } + } + require_noerr_action(error, finish, rval = KERN_FAILURE); + + /* Resolve undefined and indirect symbols */ + + /* Iterate over all unresolved symbols */ + kxld_symtab_iterator_init(&iter, symtab, + kxld_sym_is_unresolved, FALSE); + while ((sym = kxld_symtab_iterator_get_next(&iter))) { + /* Common symbols are not supported */ + if (kxld_sym_is_common(sym)) { + if (!error) { + error = TRUE; + if (kxld_object_target_supports_common_symbols(kext->kext)) { + kxld_log(kKxldLogLinking, kKxldLogErr, + "The following common symbols were not resolved:"); + } else { + kxld_log(kKxldLogLinking, kKxldLogErr, + "Common symbols are not supported in kernel extensions. " + "Use -fno-common to build your kext. " + "The following are common symbols:"); + } + } + kxld_log(kKxldLogLinking, kKxldLogErr, "\t%s", + kxld_demangle(sym->name, &demangled_name, &demangled_length)); + } else { + /* Find the address of the defined symbol */ + if (kxld_sym_is_undefined(sym)) { + name = sym->name; + } else { + name = sym->alias; + } + defined_sym = kxld_dict_find(defined_symbols, name); + + /* Resolve the symbol. If a definition cannot be found, then: + * 1) Psuedokexts log a warning and proceed + * 2) Actual kexts delay the error until validation in case vtable + * patching replaces the undefined symbol. + */ + + if (defined_sym) { + rval = kxld_sym_resolve(sym, defined_sym->link_addr); + require_noerr(rval, finish); + + if (obsolete_symbols && kxld_dict_find(obsolete_symbols, name)) { + kxld_log(kKxldLogLinking, kKxldLogWarn, + "This kext uses obsolete symbol %s.", + kxld_demangle(name, &demangled_name, &demangled_length)); + } + } else if (kxld_sym_is_weak(sym)) { + kxld_addr_t addr = 0; + + /* Make sure that the kext has referenced gOSKextUnresolved. + */ + require_action(tests_for_weak, finish, + rval = KERN_FAILURE; + kxld_log(kKxldLogLinking, kKxldLogErr, + "This kext has weak references but does not test for " + "them. Test for weak references with " + "OSKextSymbolIsResolved(). (found in )")); #if KERNEL - /* Get the address of the default weak address. - */ - addr = (kxld_addr_t) &kext_weak_symbol_referenced; -#else - /* This is run during symbol generation only, so we only - * need a filler value here. - */ - addr = 0xF00DD00D; + /* Get the address of the default weak address. + */ + addr = (kxld_addr_t) &kext_weak_symbol_referenced; +#else + /* This is run during symbol generation only, so we only + * need a filler value here. + */ + addr = 0xF00DD00D; #endif /* KERNEL */ - rval = kxld_sym_resolve(sym, addr); - require_noerr(rval, finish); - } - } - } - require_noerr_action(error, finish, rval=KERN_FAILURE); + rval = kxld_sym_resolve(sym, addr); + require_noerr(rval, finish); + } + } + } + require_noerr_action(error, finish, rval = KERN_FAILURE); - rval = KERN_SUCCESS; + rval = KERN_SUCCESS; finish: - if (demangled_name) kxld_free(demangled_name, demangled_length); + if (demangled_name) { + kxld_free(demangled_name, demangled_length); + } - return rval; + return rval; } /******************************************************************************* @@ -792,197 +811,203 @@ finish: #define kOSMetaClassVTableName "__ZTV11OSMetaClass" static kern_return_t -patch_vtables(KXLDKext *kext, KXLDDict *patched_vtables, +patch_vtables(KXLDKext *kext, KXLDDict *patched_vtables, const KXLDDict *defined_symbols) { - kern_return_t rval = KERN_FAILURE; - KXLDSymtabIterator iter; - const KXLDSymtab *symtab = NULL; - const KXLDSym *metaclass = NULL; - KXLDSym *super_metaclass_pointer = NULL; - KXLDSym *final_sym = NULL; - KXLDVTable *vtable = NULL; - KXLDVTable *super_vtable = NULL; - char class_name[KXLD_MAX_NAME_LEN]; - char super_class_name[KXLD_MAX_NAME_LEN]; - char vtable_name[KXLD_MAX_NAME_LEN]; - char super_vtable_name[KXLD_MAX_NAME_LEN]; - char final_sym_name[KXLD_MAX_NAME_LEN]; - char *demangled_name1 = NULL; - char *demangled_name2 = NULL; - size_t demangled_length1 = 0;; - size_t demangled_length2 = 0; - size_t len = 0; - u_int nvtables = 0; - u_int npatched = 0; - u_int nprogress = 0; - boolean_t failure = FALSE; - - check(kext); - check(patched_vtables); - - symtab = kxld_object_get_symtab(kext->kext); - - rval = create_vtable_index(kext); - require_noerr(rval, finish); - - /* Find each super meta class pointer symbol */ - - kxld_symtab_iterator_init(&iter, symtab, - kxld_sym_is_super_metaclass_pointer, FALSE); - nvtables = kxld_symtab_iterator_get_num_remaining(&iter); - - while (npatched < nvtables) { - npatched = 0; - nprogress = 0; - kxld_symtab_iterator_reset(&iter); - while((super_metaclass_pointer = kxld_symtab_iterator_get_next(&iter))) - { - /* Get the class name from the smc pointer */ - rval = kxld_sym_get_class_name_from_super_metaclass_pointer( - super_metaclass_pointer, class_name, sizeof(class_name)); - require_noerr(rval, finish); - - /* Get the vtable name from the class name */ - rval = kxld_sym_get_vtable_name_from_class_name(class_name, - vtable_name, sizeof(vtable_name)); - require_noerr(rval, finish); - - /* Get the vtable and make sure it hasn't been patched */ - vtable = kxld_dict_find(&kext->vtable_index, vtable_name); - require_action(vtable, finish, rval=KERN_FAILURE; - kxld_log(kKxldLogPatching, kKxldLogErr, kKxldLogMissingVtable, - vtable_name, class_name)); - - if (!vtable->is_patched) { - - /* Find the SMCP's meta class symbol */ - metaclass = get_metaclass_symbol_from_super_meta_class_pointer_symbol( - kext, super_metaclass_pointer); - require_action(metaclass, finish, rval=KERN_FAILURE); - - /* Get the super class name from the super metaclass */ - rval = kxld_sym_get_class_name_from_metaclass(metaclass, - super_class_name, sizeof(super_class_name)); - require_noerr(rval, finish); - - /* Get the super vtable name from the class name */ - rval = kxld_sym_get_vtable_name_from_class_name(super_class_name, - super_vtable_name, sizeof(super_vtable_name)); - require_noerr(rval, finish); - - /* Get the super vtable if it's been patched */ - super_vtable = kxld_dict_find(patched_vtables, super_vtable_name); - - if (failure) { - const KXLDVTable *unpatched_super_vtable; - unpatched_super_vtable = kxld_dict_find(&kext->vtable_index, - super_vtable_name); - - /* If the parent's vtable hasn't been patched, warn that - * this vtable is unpatchable because of the parent. - */ - if (!super_vtable) { - kxld_log(kKxldLogPatching, kKxldLogErr, - "The %s was not patched because its parent, " - "the %s, was not %s.", - kxld_demangle(vtable_name, &demangled_name1, - &demangled_length1), - kxld_demangle(super_vtable_name, &demangled_name2, - &demangled_length2), - (unpatched_super_vtable) ? "patchable" : "found"); - } - continue; - } - - if (!super_vtable) continue; - - /* Get the final symbol's name from the super vtable */ - rval = kxld_sym_get_final_sym_name_from_class_name(super_class_name, - final_sym_name, sizeof(final_sym_name)); - require_noerr(rval, finish); - - /* Verify that the final symbol does not exist. First check - * all the externally defined symbols, then check locally. - */ - final_sym = kxld_dict_find(defined_symbols, final_sym_name); - if (!final_sym) { - final_sym = kxld_symtab_get_locally_defined_symbol_by_name( - symtab, final_sym_name); - } - if (final_sym) { - kxld_log(kKxldLogPatching, kKxldLogErr, - "Class '%s' is a subclass of final class '%s'.", - kxld_demangle(class_name, &demangled_name1, - &demangled_length1), - kxld_demangle(super_class_name, &demangled_name2, - &demangled_length2)); - continue; - } - - /* Patch the class's vtable */ - rval = kxld_vtable_patch(vtable, super_vtable, kext->kext); - if (rval) continue; - - /* Add the class's vtable to the set of patched vtables */ - rval = kxld_dict_insert(patched_vtables, vtable->name, vtable); - require_noerr(rval, finish); - - /* Get the meta vtable name from the class name */ - rval = kxld_sym_get_meta_vtable_name_from_class_name(class_name, - vtable_name, sizeof(vtable_name)); - require_noerr(rval, finish); - - /* Get the meta vtable. Whether or not it should exist has already - * been tested in create_vtables(), so if it doesn't exist and we're - * still running, we can safely skip it. - */ - vtable = kxld_dict_find(&kext->vtable_index, vtable_name); - if (!vtable) { - ++nprogress; - ++npatched; - continue; - } - require_action(!vtable->is_patched, finish, rval=KERN_FAILURE); - - /* There is no way to look up a metaclass vtable at runtime, but - * we know that every class's metaclass inherits directly from - * OSMetaClass, so we just hardcode that vtable name here. - */ - len = strlcpy(super_vtable_name, kOSMetaClassVTableName, - sizeof(super_vtable_name)); - require_action(len == const_strlen(kOSMetaClassVTableName), - finish, rval=KERN_FAILURE); - - /* Get the super meta vtable */ - super_vtable = kxld_dict_find(patched_vtables, super_vtable_name); - require_action(super_vtable && super_vtable->is_patched, - finish, rval=KERN_FAILURE); - - /* Patch the meta class's vtable */ - rval = kxld_vtable_patch(vtable, super_vtable, kext->kext); - require_noerr(rval, finish); - - /* Add the MetaClass's vtable to the set of patched vtables */ - rval = kxld_dict_insert(patched_vtables, vtable->name, vtable); - require_noerr(rval, finish); - - ++nprogress; - } - - ++npatched; - } - - require_action(!failure, finish, rval=KERN_FAILURE); - failure = (nprogress == 0); - } - - rval = KERN_SUCCESS; + kern_return_t rval = KERN_FAILURE; + KXLDSymtabIterator iter; + const KXLDSymtab *symtab = NULL; + const KXLDSym *metaclass = NULL; + KXLDSym *super_metaclass_pointer = NULL; + KXLDSym *final_sym = NULL; + KXLDVTable *vtable = NULL; + KXLDVTable *super_vtable = NULL; + char class_name[KXLD_MAX_NAME_LEN]; + char super_class_name[KXLD_MAX_NAME_LEN]; + char vtable_name[KXLD_MAX_NAME_LEN]; + char super_vtable_name[KXLD_MAX_NAME_LEN]; + char final_sym_name[KXLD_MAX_NAME_LEN]; + char *demangled_name1 = NULL; + char *demangled_name2 = NULL; + size_t demangled_length1 = 0;; + size_t demangled_length2 = 0; + size_t len = 0; + u_int nvtables = 0; + u_int npatched = 0; + u_int nprogress = 0; + boolean_t failure = FALSE; + + check(kext); + check(patched_vtables); + + symtab = kxld_object_get_symtab(kext->kext); + + rval = create_vtable_index(kext); + require_noerr(rval, finish); + + /* Find each super meta class pointer symbol */ + + kxld_symtab_iterator_init(&iter, symtab, + kxld_sym_is_super_metaclass_pointer, FALSE); + nvtables = kxld_symtab_iterator_get_num_remaining(&iter); + + while (npatched < nvtables) { + npatched = 0; + nprogress = 0; + kxld_symtab_iterator_reset(&iter); + while ((super_metaclass_pointer = kxld_symtab_iterator_get_next(&iter))) { + /* Get the class name from the smc pointer */ + rval = kxld_sym_get_class_name_from_super_metaclass_pointer( + super_metaclass_pointer, class_name, sizeof(class_name)); + require_noerr(rval, finish); + + /* Get the vtable name from the class name */ + rval = kxld_sym_get_vtable_name_from_class_name(class_name, + vtable_name, sizeof(vtable_name)); + require_noerr(rval, finish); + + /* Get the vtable and make sure it hasn't been patched */ + vtable = kxld_dict_find(&kext->vtable_index, vtable_name); + require_action(vtable, finish, rval = KERN_FAILURE; + kxld_log(kKxldLogPatching, kKxldLogErr, kKxldLogMissingVtable, + vtable_name, class_name)); + + if (!vtable->is_patched) { + /* Find the SMCP's meta class symbol */ + metaclass = get_metaclass_symbol_from_super_meta_class_pointer_symbol( + kext, super_metaclass_pointer); + require_action(metaclass, finish, rval = KERN_FAILURE); + + /* Get the super class name from the super metaclass */ + rval = kxld_sym_get_class_name_from_metaclass(metaclass, + super_class_name, sizeof(super_class_name)); + require_noerr(rval, finish); + + /* Get the super vtable name from the class name */ + rval = kxld_sym_get_vtable_name_from_class_name(super_class_name, + super_vtable_name, sizeof(super_vtable_name)); + require_noerr(rval, finish); + + /* Get the super vtable if it's been patched */ + super_vtable = kxld_dict_find(patched_vtables, super_vtable_name); + + if (failure) { + const KXLDVTable *unpatched_super_vtable; + unpatched_super_vtable = kxld_dict_find(&kext->vtable_index, + super_vtable_name); + + /* If the parent's vtable hasn't been patched, warn that + * this vtable is unpatchable because of the parent. + */ + if (!super_vtable) { + kxld_log(kKxldLogPatching, kKxldLogErr, + "The %s was not patched because its parent, " + "the %s, was not %s.", + kxld_demangle(vtable_name, &demangled_name1, + &demangled_length1), + kxld_demangle(super_vtable_name, &demangled_name2, + &demangled_length2), + (unpatched_super_vtable) ? "patchable" : "found"); + } + continue; + } + + if (!super_vtable) { + continue; + } + + /* Get the final symbol's name from the super vtable */ + rval = kxld_sym_get_final_sym_name_from_class_name(super_class_name, + final_sym_name, sizeof(final_sym_name)); + require_noerr(rval, finish); + + /* Verify that the final symbol does not exist. First check + * all the externally defined symbols, then check locally. + */ + final_sym = kxld_dict_find(defined_symbols, final_sym_name); + if (!final_sym) { + final_sym = kxld_symtab_get_locally_defined_symbol_by_name( + symtab, final_sym_name); + } + if (final_sym) { + kxld_log(kKxldLogPatching, kKxldLogErr, + "Class '%s' is a subclass of final class '%s'.", + kxld_demangle(class_name, &demangled_name1, + &demangled_length1), + kxld_demangle(super_class_name, &demangled_name2, + &demangled_length2)); + continue; + } + + /* Patch the class's vtable */ + rval = kxld_vtable_patch(vtable, super_vtable, kext->kext); + if (rval) { + continue; + } + + /* Add the class's vtable to the set of patched vtables */ + rval = kxld_dict_insert(patched_vtables, vtable->name, vtable); + require_noerr(rval, finish); + + /* Get the meta vtable name from the class name */ + rval = kxld_sym_get_meta_vtable_name_from_class_name(class_name, + vtable_name, sizeof(vtable_name)); + require_noerr(rval, finish); + + /* Get the meta vtable. Whether or not it should exist has already + * been tested in create_vtables(), so if it doesn't exist and we're + * still running, we can safely skip it. + */ + vtable = kxld_dict_find(&kext->vtable_index, vtable_name); + if (!vtable) { + ++nprogress; + ++npatched; + continue; + } + require_action(!vtable->is_patched, finish, rval = KERN_FAILURE); + + /* There is no way to look up a metaclass vtable at runtime, but + * we know that every class's metaclass inherits directly from + * OSMetaClass, so we just hardcode that vtable name here. + */ + len = strlcpy(super_vtable_name, kOSMetaClassVTableName, + sizeof(super_vtable_name)); + require_action(len == const_strlen(kOSMetaClassVTableName), + finish, rval = KERN_FAILURE); + + /* Get the super meta vtable */ + super_vtable = kxld_dict_find(patched_vtables, super_vtable_name); + require_action(super_vtable && super_vtable->is_patched, + finish, rval = KERN_FAILURE); + + /* Patch the meta class's vtable */ + rval = kxld_vtable_patch(vtable, super_vtable, kext->kext); + require_noerr(rval, finish); + + /* Add the MetaClass's vtable to the set of patched vtables */ + rval = kxld_dict_insert(patched_vtables, vtable->name, vtable); + require_noerr(rval, finish); + + ++nprogress; + } + + ++npatched; + } + + require_action(!failure, finish, rval = KERN_FAILURE); + failure = (nprogress == 0); + } + + rval = KERN_SUCCESS; finish: - if (demangled_name1) kxld_free(demangled_name1, demangled_length1); - if (demangled_name2) kxld_free(demangled_name2, demangled_length2); - - return rval; + if (demangled_name1) { + kxld_free(demangled_name1, demangled_length1); + } + if (demangled_name2) { + kxld_free(demangled_name2, demangled_length2); + } + + return rval; } /******************************************************************************* @@ -990,30 +1015,30 @@ finish: static kern_return_t create_vtable_index(KXLDKext *kext) { - kern_return_t rval = KERN_FAILURE; - KXLDVTable *vtable = NULL; - u_int i = 0; - - if (kext->vtable_index_created) { - rval = KERN_SUCCESS; - goto finish; - } - - /* Map vtable names to the vtable structures */ - rval = kxld_dict_init(&kext->vtable_index, kxld_dict_string_hash, - kxld_dict_string_cmp, kext->vtables.nitems); - require_noerr(rval, finish); - - for (i = 0; i < kext->vtables.nitems; ++i) { - vtable = kxld_array_get_item(&kext->vtables, i); - rval = kxld_dict_insert(&kext->vtable_index, vtable->name, vtable); - require_noerr(rval, finish); - } - - kext->vtable_index_created = TRUE; - rval = KERN_SUCCESS; + kern_return_t rval = KERN_FAILURE; + KXLDVTable *vtable = NULL; + u_int i = 0; + + if (kext->vtable_index_created) { + rval = KERN_SUCCESS; + goto finish; + } + + /* Map vtable names to the vtable structures */ + rval = kxld_dict_init(&kext->vtable_index, kxld_dict_string_hash, + kxld_dict_string_cmp, kext->vtables.nitems); + require_noerr(rval, finish); + + for (i = 0; i < kext->vtables.nitems; ++i) { + vtable = kxld_array_get_item(&kext->vtables, i); + rval = kxld_dict_insert(&kext->vtable_index, vtable->name, vtable); + require_noerr(rval, finish); + } + + kext->vtable_index_created = TRUE; + rval = KERN_SUCCESS; finish: - return rval; + return rval; } /******************************************************************************* @@ -1022,60 +1047,69 @@ static const KXLDSym * get_metaclass_symbol_from_super_meta_class_pointer_symbol(KXLDKext *kext, KXLDSym *super_metaclass_pointer_sym) { - kern_return_t rval = KERN_FAILURE; - const KXLDReloc *reloc = NULL; - const KXLDSect *sect = NULL; - const KXLDSym *metaclass = NULL; - - check(kext); - check(super_metaclass_pointer_sym); - - /* Get the relocation entry that fills in the super metaclass pointer. */ - reloc = kxld_object_get_reloc_at_symbol(kext->kext, - super_metaclass_pointer_sym); - require_action(reloc, finish, rval=KERN_FAILURE); - - /* Get the section of the super metaclass pointer. */ - sect = kxld_object_get_section_by_index(kext->kext, - super_metaclass_pointer_sym->sectnum); - require_action(sect, finish, rval=KERN_FAILURE); - - /* Get the symbol that will be filled into the super metaclass pointer. */ - metaclass = kxld_object_get_symbol_of_reloc(kext->kext, reloc, sect); + kern_return_t rval = KERN_FAILURE; + const KXLDReloc *reloc = NULL; + const KXLDSect *sect = NULL; + const KXLDSym *metaclass = NULL; + + check(kext); + check(super_metaclass_pointer_sym); + + /* Get the relocation entry that fills in the super metaclass pointer. */ + reloc = kxld_object_get_reloc_at_symbol(kext->kext, + super_metaclass_pointer_sym); + require_action(reloc, finish, rval = KERN_FAILURE); + + /* Get the section of the super metaclass pointer. */ + sect = kxld_object_get_section_by_index(kext->kext, + super_metaclass_pointer_sym->sectnum); + require_action(sect, finish, rval = KERN_FAILURE); + + /* Get the symbol that will be filled into the super metaclass pointer. */ + metaclass = kxld_object_get_symbol_of_reloc(kext->kext, reloc, sect); + + finish: - return metaclass; + if (metaclass == NULL) { + kxld_log(kKxldLogLinking, kKxldLogErr, + "metaclass == NULL kxld_sym %s <%s>", + super_metaclass_pointer_sym->name, __func__); + } + return metaclass; } + /******************************************************************************* *******************************************************************************/ static kern_return_t validate_symbols(KXLDKext *kext) { - kern_return_t rval = KERN_FAILURE; - KXLDSymtabIterator iter; - KXLDSym *sym = NULL; - u_int error = FALSE; - char *demangled_name = NULL; - size_t demangled_length = 0; - - /* Check for any unresolved symbols */ - kxld_symtab_iterator_init(&iter, kxld_object_get_symtab(kext->kext), - kxld_sym_is_unresolved, FALSE); - while ((sym = kxld_symtab_iterator_get_next(&iter))) { - if (!error) { - error = TRUE; - kxld_log(kKxldLogLinking, kKxldLogErr, - "The following symbols are unresolved for this kext:"); - } - kxld_log(kKxldLogLinking, kKxldLogErr, "\t%s", - kxld_demangle(sym->name, &demangled_name, &demangled_length)); - } - require_noerr_action(error, finish, rval=KERN_FAILURE); - - rval = KERN_SUCCESS; + kern_return_t rval = KERN_FAILURE; + KXLDSymtabIterator iter; + KXLDSym *sym = NULL; + u_int error = FALSE; + char *demangled_name = NULL; + size_t demangled_length = 0; + + /* Check for any unresolved symbols */ + kxld_symtab_iterator_init(&iter, kxld_object_get_symtab(kext->kext), + kxld_sym_is_unresolved, FALSE); + while ((sym = kxld_symtab_iterator_get_next(&iter))) { + if (!error) { + error = TRUE; + kxld_log(kKxldLogLinking, kKxldLogErr, + "The following symbols are unresolved for this kext:"); + } + kxld_log(kKxldLogLinking, kKxldLogErr, "\t%s", + kxld_demangle(sym->name, &demangled_name, &demangled_length)); + } + require_noerr_action(error, finish, rval = KERN_FAILURE); + + rval = KERN_SUCCESS; finish: - if (demangled_name) kxld_free(demangled_name, demangled_length); - return rval; + if (demangled_name) { + kxld_free(demangled_name, demangled_length); + } + return rval; } -