/*
- * 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
* 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,
* 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 <string.h>
#include <mach/mach_init.h>
#include <mach-o/arch.h>
#include <mach-o/swap.h>
+
#endif /* KERNEL */
#define DEBUG_ASSERT_COMPONENT_NAME_STRING "kxld"
#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;
};
/*******************************************************************************
*******************************************************************************/
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);
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;
}
/*******************************************************************************
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;
}
/*******************************************************************************
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;
}
/*******************************************************************************
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;
}
/*******************************************************************************
* 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 <libkern/OSKextLib.h>)"));
#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;
}
/*******************************************************************************
#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;
}
/*******************************************************************************
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;
}
/*******************************************************************************
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;
}
-