Refactor mach0 loading of relocs ##bin

This commit is contained in:
Luc Tielen 2023-04-17 16:20:51 +02:00 committed by pancake
parent 86d77e2a54
commit 7ee8fb77a2
7 changed files with 70 additions and 78 deletions

View File

@ -2194,6 +2194,9 @@ void *MACH0_(mach0_free)(struct MACH0_(obj_t) *mo) {
}
r_list_free (mo->cached_segments);
mo->cached_segments = NULL;
if (mo->relocs_loaded) {
r_skiplist_free (mo->relocs_cache);
}
if (mo->chained_starts) {
for (i = 0; i < mo->nsegs && i < mo->segs_count; i++) {
if (mo->chained_starts[i]) {
@ -3540,8 +3543,7 @@ static bool is_valid_ordinal_table_size(ut64 size) {
return size > 0 && size <= UT16_MAX;
}
RSkipList *MACH0_(get_relocs)(struct MACH0_(obj_t) *bin) {
RSkipList *relocs = NULL;
static inline bool _load_relocations(struct MACH0_(obj_t) *bin) {
RPVector *threaded_binds = NULL;
size_t wordsize = get_word_size (bin);
if (bin->dyld_info) {
@ -3554,7 +3556,7 @@ RSkipList *MACH0_(get_relocs)(struct MACH0_(obj_t) *bin) {
CASE(16);
CASE(32);
CASE(64);
default: return NULL;
default: return false;
}
#undef CASE
bind_size = bin->dyld_info->bind_size;
@ -3562,40 +3564,35 @@ RSkipList *MACH0_(get_relocs)(struct MACH0_(obj_t) *bin) {
weak_size = bin->dyld_info->weak_bind_size;
if (!bind_size && !lazy_size) {
return NULL;
return false;
}
if ((bind_size + lazy_size) < 1) {
return NULL;
return false;
}
if (bin->dyld_info->bind_off > bin->size || bin->dyld_info->bind_off + bind_size > bin->size) {
return NULL;
return false;
}
if (bin->dyld_info->lazy_bind_off > bin->size || \
bin->dyld_info->lazy_bind_off + lazy_size > bin->size) {
return NULL;
return false;
}
if (bin->dyld_info->bind_off + bind_size + lazy_size > bin->size) {
return NULL;
return false;
}
if (bin->dyld_info->weak_bind_off + weak_size > bin->size) {
return NULL;
return false;
}
ut64 amount = bind_size + lazy_size + weak_size;
if (amount == 0 || amount > UT32_MAX) {
return NULL;
return false;
}
if (!bin->segs) {
return NULL;
}
relocs = r_skiplist_new ((RListFree) &free, (RListComparator) &reloc_comparator);
if (!relocs) {
return NULL;
return false;
}
opcodes = calloc (1, amount + 1);
if (!opcodes) {
r_skiplist_free (relocs);
return NULL;
return false;
}
int len = r_buf_read_at (bin->b, bin->dyld_info->bind_off, opcodes, bind_size);
@ -3604,8 +3601,7 @@ RSkipList *MACH0_(get_relocs)(struct MACH0_(obj_t) *bin) {
if (len < amount) {
R_LOG_ERROR ("read (dyld_info bind) at 0x%08"PFMT64x, (ut64)(size_t)bin->dyld_info->bind_off);
R_FREE (opcodes);
r_skiplist_free (relocs);
return NULL;
return false;
}
size_t partition_sizes[] = {bind_size, lazy_size, weak_size};
@ -3720,7 +3716,7 @@ RSkipList *MACH0_(get_relocs)(struct MACH0_(obj_t) *bin) {
if (addend != -1) {
reloc->addend = addend;
}
r_skiplist_insert (relocs, reloc);
r_skiplist_insert (bin->relocs_cache, reloc);
}
addr += delta * wordsize;
if (!delta) {
@ -3788,9 +3784,8 @@ RSkipList *MACH0_(get_relocs)(struct MACH0_(obj_t) *bin) {
bprintf ("Error: BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB"
" has unexistent segment %d\n", seg_idx);
free (opcodes);
r_skiplist_free (relocs);
r_pvector_free (threaded_binds);
return NULL; // early exit to avoid future mayhem
return false; // early exit to avoid future mayhem
}
addr = bin->segs[seg_idx].vmaddr + read_uleb128 (&p, end);
segment_end_addr = bin->segs[seg_idx].vmaddr \
@ -3825,7 +3820,7 @@ RSkipList *MACH0_(get_relocs)(struct MACH0_(obj_t) *bin) {
if (threaded_binds)\
r_pvector_set (threaded_binds, sym_ord, reloc);\
else\
r_skiplist_insert (relocs, reloc);\
r_skiplist_insert (bin->relocs_cache, reloc);\
} while (0)
case BIND_OPCODE_DO_BIND:
if (!threaded_binds && addr >= segment_end_addr) {
@ -3872,7 +3867,7 @@ RSkipList *MACH0_(get_relocs)(struct MACH0_(obj_t) *bin) {
bprintf ("Error: unknown bind opcode 0x%02x in dyld_info\n", *p);
R_FREE (opcodes);
r_pvector_free (threaded_binds);
return relocs;
return false;
}
}
@ -3890,12 +3885,6 @@ RSkipList *MACH0_(get_relocs)(struct MACH0_(obj_t) *bin) {
if (amount < 0) {
amount = 0;
}
if (!relocs) {
relocs = r_skiplist_new ((RListFree) &free, (RListComparator) &reloc_comparator);
if (!relocs) {
goto beach;
}
}
for (j = 0; j < amount; j++) {
struct reloc_t *reloc = R_NEW0 (struct reloc_t);
if (!reloc) {
@ -3903,7 +3892,7 @@ RSkipList *MACH0_(get_relocs)(struct MACH0_(obj_t) *bin) {
}
if (parse_import_ptr (bin, reloc, bin->dysymtab.iundefsym + j)) {
reloc->ord = j;
r_skiplist_insert_autofree (relocs, reloc);
r_skiplist_insert_autofree (bin->relocs_cache, reloc);
} else {
R_FREE (reloc);
}
@ -3911,27 +3900,37 @@ RSkipList *MACH0_(get_relocs)(struct MACH0_(obj_t) *bin) {
}
if (bin->symtab && bin->dysymtab.extreloff && bin->dysymtab.nextrel) {
if (!relocs) {
relocs = r_skiplist_new ((RListFree) &free, (RListComparator) &reloc_comparator);
if (!relocs) {
goto beach;
}
}
parse_relocation_info (bin, relocs, bin->dysymtab.extreloff, bin->dysymtab.nextrel);
parse_relocation_info (bin, bin->relocs_cache, bin->dysymtab.extreloff, bin->dysymtab.nextrel);
}
if (!bin->dyld_info && bin->chained_starts && bin->nsegs && bin->fixups_offset) {
if (!relocs) {
relocs = r_skiplist_new ((RListFree) &free, (RListComparator) &reloc_comparator);
if (!relocs) {
goto beach;
}
}
walk_bind_chains (bin, relocs);
walk_bind_chains (bin, bin->relocs_cache);
}
beach:
r_pvector_free (threaded_binds);
return relocs;
return true;
}
const RSkipList *MACH0_(load_relocs)(struct MACH0_(obj_t) *bin) {
r_return_val_if_fail (bin, NULL);
if (bin->relocs_loaded) {
return bin->relocs_cache;
}
bin->relocs_loaded = true;
bin->relocs_cache = r_skiplist_new ((RListFree) free, (RListComparator) reloc_comparator);
if (!bin->relocs_cache) {
return NULL;
}
bool is_success = _load_relocations (bin);
if (is_success) {
return bin->relocs_cache;
}
return NULL;
}
struct addr_t *MACH0_(get_entrypoint)(struct MACH0_(obj_t) *bin) {

View File

@ -62,7 +62,6 @@ struct reloc_t {
st64 addend;
ut8 type;
int ord;
int last;
char name[256];
bool external;
bool pc_relative;
@ -180,6 +179,8 @@ struct MACH0_(obj_t) {
RVector sections_cache;
bool imports_loaded;
RPVector imports_cache;
bool relocs_loaded;
RSkipList *relocs_cache;
RList *reloc_fixups;
ut8 *internal_buffer;
int internal_buffer_size;
@ -247,7 +248,7 @@ RList *MACH0_(get_segments)(RBinFile *bf, struct MACH0_(obj_t) *bin);
const RVector *MACH0_(load_symbols)(RBinFile *bf, struct MACH0_(obj_t) *bin);
void MACH0_(pull_symbols)(struct MACH0_(obj_t) *mo, RBinSymbolCallback cb, void *user);
const RPVector *MACH0_(load_imports)(RBinFile* bf, struct MACH0_(obj_t) *bin);
RSkipList *MACH0_(get_relocs)(struct MACH0_(obj_t) *bin);
const RSkipList *MACH0_(load_relocs)(struct MACH0_(obj_t) *bin);
struct addr_t *MACH0_(get_entrypoint)(struct MACH0_(obj_t) *bin);
const RPVector *MACH0_(load_libs)(struct MACH0_(obj_t) *bin);
ut64 MACH0_(get_baddr)(struct MACH0_(obj_t) *bin);

View File

@ -112,7 +112,7 @@ static void get_objc_property_list(mach0_ut p, RBinFile *bf, RBinClass *klass);
static void get_method_list_t(mach0_ut p, RBinFile *bf, char *class_name, RBinClass *klass, bool is_static, objc_cache_opt_info *oi);
static void get_protocol_list_t(mach0_ut p, RBinFile *bf, RBinClass *klass, objc_cache_opt_info *oi);
static void get_class_ro_t(mach0_ut p, RBinFile *bf, ut32 *is_meta_class, RBinClass *klass, objc_cache_opt_info *oi);
static RList *MACH0_(parse_categories)(RBinFile *bf, RSkipList *relocs, objc_cache_opt_info *oi);
static RList *MACH0_(parse_categories)(RBinFile *bf, const RSkipList *relocs, objc_cache_opt_info *oi);
static bool read_ptr_pa(RBinFile *bf, ut64 paddr, mach0_ut *out);
static bool read_ptr_va(RBinFile *bf, ut64 vaddr, mach0_ut *out);
static char *read_str(RBinFile *bf, mach0_ut p, ut32 *offset, ut32 *left);
@ -1137,7 +1137,7 @@ static mach0_ut get_isa_value(void) {
return 0;
}
void MACH0_(get_class_t)(mach0_ut p, RBinFile *bf, RBinClass *klass, bool dupe, RSkipList *relocs, objc_cache_opt_info *oi) {
void MACH0_(get_class_t)(mach0_ut p, RBinFile *bf, RBinClass *klass, bool dupe, const RSkipList *relocs, objc_cache_opt_info *oi) {
struct MACH0_(SClass) c = {0};
const int size = sizeof (struct MACH0_(SClass));
mach0_ut r = 0;
@ -1399,8 +1399,7 @@ RList *MACH0_(parse_classes)(RBinFile *bf, objc_cache_opt_info *oi) {
}
bool bigendian = bf->o->info->big_endian;
RSkipList *relocs = MACH0_(get_relocs) (bf->o->bin_obj);
const RSkipList *relocs = MACH0_(load_relocs) (bf->o->bin_obj);
ret = MACH0_(parse_categories) (bf, relocs, oi);
/* check if it's Swift */
@ -1410,7 +1409,6 @@ RList *MACH0_(parse_classes)(RBinFile *bf, objc_cache_opt_info *oi) {
const RVector *sections = MACH0_(load_sections) (bf->o->bin_obj);
if (!sections) {
r_skiplist_free (relocs);
return ret;
}
@ -1526,18 +1524,16 @@ RList *MACH0_(parse_classes)(RBinFile *bf, objc_cache_opt_info *oi) {
}
r_list_append (ret, klass);
}
r_skiplist_free (relocs);
return ret;
get_classes_error:
r_list_free (sctns);
r_list_free (ret);
r_skiplist_free (relocs);
// XXX DOUBLE FREE r_bin_class_free (klass);
return NULL;
}
static RList *MACH0_(parse_categories)(RBinFile *bf, RSkipList *relocs, objc_cache_opt_info *oi) {
static RList *MACH0_(parse_categories)(RBinFile *bf, const RSkipList *relocs, objc_cache_opt_info *oi) {
r_return_val_if_fail (bf && bf->o && bf->o->bin_obj && bf->o->info, NULL);
RList /*<RBinClass>*/ *ret = NULL;
@ -1629,7 +1625,7 @@ error:
return NULL;
}
void MACH0_(get_category_t)(mach0_ut p, RBinFile *bf, RBinClass *klass, RSkipList *relocs, objc_cache_opt_info *oi) {
void MACH0_(get_category_t)(mach0_ut p, RBinFile *bf, RBinClass *klass, const RSkipList *relocs, objc_cache_opt_info *oi) {
r_return_if_fail (bf && bf->o && bf->o->info);
struct MACH0_(SCategory) c = {0};

View File

@ -18,7 +18,7 @@
#define MACH0_CLASSES_H
R_API RList *MACH0_(parse_classes)(RBinFile *bf, objc_cache_opt_info *oi);
R_API void MACH0_(get_class_t)(mach0_ut p, RBinFile *bf, RBinClass *klass, bool dupe, RSkipList *relocs, objc_cache_opt_info *oi);
R_API void MACH0_(get_category_t)(mach0_ut p, RBinFile *bf, RBinClass *klass, RSkipList *relocs, objc_cache_opt_info *oi);
R_API void MACH0_(get_class_t)(mach0_ut p, RBinFile *bf, RBinClass *klass, bool dupe, const RSkipList *relocs, objc_cache_opt_info *oi);
R_API void MACH0_(get_category_t)(mach0_ut p, RBinFile *bf, RBinClass *klass, const RSkipList *relocs, objc_cache_opt_info *oi);
#endif // MACH0_CLASSES_H

View File

@ -282,7 +282,7 @@ static RList *relocs(RBinFile *bf) {
return NULL;
}
ret->free = free;
RSkipList *relocs = MACH0_(get_relocs) (bf->o->bin_obj);
const RSkipList *relocs = MACH0_(load_relocs) (bf->o->bin_obj);
if (!relocs) {
return ret;
}
@ -317,8 +317,6 @@ static RList *relocs(RBinFile *bf) {
r_list_append (ret, ptr);
}
r_skiplist_free (relocs);
return ret;
}
@ -474,21 +472,19 @@ static RList* patch_relocs(RBin *b) {
const bool apply_relocs = io->cached; // true; // !mo->b->readonly;
const bool cache_relocs = io->cached;
RSkipList *all_relocs = MACH0_(get_relocs)(mo);
const RSkipList *all_relocs = MACH0_(load_relocs)(mo);
if (!all_relocs) {
return NULL;
}
RList *ext_relocs = r_list_new ();
if (!ext_relocs) {
goto beach;
}
RPVector ext_relocs;
r_pvector_init (&ext_relocs, NULL);
RSkipListNode *it;
struct reloc_t *reloc;
r_skiplist_foreach (all_relocs, it, reloc) {
if (!reloc->external) {
continue;
}
r_list_append (ext_relocs, reloc);
r_pvector_push (&ext_relocs, reloc);
}
if (mo->reloc_fixups && r_list_length (mo->reloc_fixups) > 0) {
if (!apply_relocs) {
@ -519,7 +515,7 @@ static RList* patch_relocs(RBin *b) {
}
}
}
ut64 num_ext_relocs = r_list_length (ext_relocs);
ut64 num_ext_relocs = r_pvector_length (&ext_relocs);
if (!num_ext_relocs) {
goto beach;
}
@ -569,8 +565,9 @@ static RList* patch_relocs(RBin *b) {
goto beach;
}
ut64 vaddr = n_vaddr;
RListIter *liter;
r_list_foreach (ext_relocs, liter, reloc) {
void **ext_reloc_iter;
r_pvector_foreach (&ext_relocs, ext_reloc_iter) {
reloc = *ext_reloc_iter;
bool found = false;
ut64 sym_addr = ht_uu_find (relocs_by_sym, reloc->ord, &found);
if (!found || !sym_addr) {
@ -599,13 +596,12 @@ static RList* patch_relocs(RBin *b) {
goto beach;
}
ht_uu_free (relocs_by_sym);
r_list_free (ext_relocs);
r_skiplist_free (all_relocs);
r_pvector_fini (&ext_relocs);
// XXX r_io_desc_free (gotr2desc);
return ret;
beach:
r_list_free (ext_relocs);
r_skiplist_free (all_relocs);
r_pvector_fini (&ext_relocs);
r_io_desc_free (gotr2desc);
r_list_free (ret);
ht_uu_free (relocs_by_sym);

View File

@ -36,7 +36,7 @@ R_API RSkipListNode* r_skiplist_insert(RSkipList* list, void* data);
R_API bool r_skiplist_insert_autofree(RSkipList* list, void* data);
R_API bool r_skiplist_delete(RSkipList* list, void* data);
R_API bool r_skiplist_delete_node(RSkipList *list, RSkipListNode *node);
R_API RSkipListNode* r_skiplist_find(RSkipList* list, void* data);
R_API RSkipListNode* r_skiplist_find(const RSkipList* list, void* data);
R_API RSkipListNode* r_skiplist_find_geq(RSkipList* list, void* data);
R_API RSkipListNode* r_skiplist_find_leq(RSkipList* list, void* data);
R_API void r_skiplist_join(RSkipList *l1, RSkipList *l2);

View File

@ -48,7 +48,7 @@ static inline void init_head(RSkipListNode *head) {
//
// NOTE: `updates` should be big enough to contain `list->list_level + 1`
// elements, when provided.
static RSkipListNode *find_insertpoint(RSkipList *list, void *data, RSkipListNode **updates, bool by_data) {
static RSkipListNode *find_insertpoint(const RSkipList *list, void *data, RSkipListNode **updates, bool by_data) {
RSkipListNode *x = list->head;
int i;
@ -216,7 +216,7 @@ R_API bool r_skiplist_delete_node(RSkipList *list, RSkipListNode *node) {
return delete_element (list, node, false);
}
R_API RSkipListNode* r_skiplist_find(RSkipList* list, void* data) {
R_API RSkipListNode* r_skiplist_find(const RSkipList* list, void* data) {
r_return_val_if_fail (list, NULL);
RSkipListNode* x = find_insertpoint (list, data, NULL, true);
if (x != list->head && list->compare (x->data, data) == 0) {