Skip to content

Commit fda9c70

Browse files
author
Pedro A Osuna
committed
Fix memory issues causing EXC_BAD_ACCESS
Fix grabbed from PR facebook#84
1 parent 8ef82f0 commit fda9c70

File tree

1 file changed

+38
-24
lines changed

1 file changed

+38
-24
lines changed

fishhook.c

Lines changed: 38 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
#include <mach-o/dyld.h>
3636
#include <mach-o/loader.h>
3737
#include <mach-o/nlist.h>
38+
#include <pthread.h>
3839

3940
#ifdef __LP64__
4041
typedef struct mach_header_64 mach_header_t;
@@ -54,13 +55,18 @@ typedef struct nlist nlist_t;
5455
#define SEG_DATA_CONST "__DATA_CONST"
5556
#endif
5657

58+
#ifndef SEG_AUTH_CONST
59+
#define SEG_AUTH_CONST "__AUTH_CONST"
60+
#endif
61+
5762
struct rebindings_entry {
5863
struct rebinding *rebindings;
5964
size_t rebindings_nel;
6065
struct rebindings_entry *next;
6166
};
6267

6368
static struct rebindings_entry *_rebindings_head;
69+
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
6470

6571
static int prepend_rebindings(struct rebindings_entry **rebindings_head,
6672
struct rebinding rebindings[],
@@ -90,7 +96,7 @@ static vm_prot_t get_protection(void *sectionStart) {
9096
mach_msg_type_number_t count = VM_REGION_BASIC_INFO_COUNT_64;
9197
vm_region_basic_info_data_64_t info;
9298
kern_return_t info_ret = vm_region_64(
93-
task, &address, &size, VM_REGION_BASIC_INFO_64, (vm_region_info_64_t)&info, &count, &object);
99+
task, &address, &size, VM_REGION_BASIC_INFO_64, (vm_region_info_64_t)&info, &count, &object);
94100
#else
95101
mach_msg_type_number_t count = VM_REGION_BASIC_INFO_COUNT;
96102
vm_region_basic_info_data_t info;
@@ -109,17 +115,23 @@ static void perform_rebinding_with_section(struct rebindings_entry *rebindings,
109115
char *strtab,
110116
uint32_t *indirect_symtab) {
111117
const bool isDataConst = strcmp(section->segname, SEG_DATA_CONST) == 0;
118+
const bool isAuthConst = strcmp(section->segname, SEG_AUTH_CONST) == 0;
112119
uint32_t *indirect_symbol_indices = indirect_symtab + section->reserved1;
113120
void **indirect_symbol_bindings = (void **)((uintptr_t)slide + section->addr);
114121
vm_prot_t oldProtection = VM_PROT_READ;
115-
if (isDataConst) {
116-
oldProtection = get_protection(rebindings);
117-
mprotect(indirect_symbol_bindings, section->size, PROT_READ | PROT_WRITE);
122+
vm_size_t trunc_address = (vm_size_t)indirect_symbol_bindings;
123+
vm_size_t trunc_size = 0;
124+
if (isDataConst || isAuthConst) {
125+
trunc_address = trunc_page((vm_size_t)indirect_symbol_bindings);
126+
trunc_size =(vm_size_t)indirect_symbol_bindings -trunc_address;
127+
pthread_mutex_lock(&mutex);
128+
oldProtection = get_protection((void *)trunc_address);
129+
mprotect((void *)trunc_address, section->size+trunc_size, PROT_READ | PROT_WRITE);
118130
}
119131
for (uint i = 0; i < section->size / sizeof(void *); i++) {
120132
uint32_t symtab_index = indirect_symbol_indices[i];
121133
if (symtab_index == INDIRECT_SYMBOL_ABS || symtab_index == INDIRECT_SYMBOL_LOCAL ||
122-
symtab_index == (INDIRECT_SYMBOL_LOCAL | INDIRECT_SYMBOL_ABS)) {
134+
symtab_index == (INDIRECT_SYMBOL_LOCAL | INDIRECT_SYMBOL_ABS)) {
123135
continue;
124136
}
125137
uint32_t strtab_offset = symtab[symtab_index].n_un.n_strx;
@@ -142,7 +154,7 @@ static void perform_rebinding_with_section(struct rebindings_entry *rebindings,
142154
}
143155
symbol_loop:;
144156
}
145-
if (isDataConst) {
157+
if (isDataConst || isAuthConst) {
146158
int protection = 0;
147159
if (oldProtection & VM_PROT_READ) {
148160
protection |= PROT_READ;
@@ -153,7 +165,8 @@ static void perform_rebinding_with_section(struct rebindings_entry *rebindings,
153165
if (oldProtection & VM_PROT_EXECUTE) {
154166
protection |= PROT_EXEC;
155167
}
156-
mprotect(indirect_symbol_bindings, section->size, protection);
168+
mprotect((void *)trunc_address, section->size+trunc_size, protection);
169+
pthread_mutex_unlock(&mutex);
157170
}
158171
}
159172

@@ -164,12 +177,12 @@ static void rebind_symbols_for_image(struct rebindings_entry *rebindings,
164177
if (dladdr(header, &info) == 0) {
165178
return;
166179
}
167-
180+
168181
segment_command_t *cur_seg_cmd;
169182
segment_command_t *linkedit_segment = NULL;
170183
struct symtab_command* symtab_cmd = NULL;
171184
struct dysymtab_command* dysymtab_cmd = NULL;
172-
185+
173186
uintptr_t cur = (uintptr_t)header + sizeof(mach_header_t);
174187
for (uint i = 0; i < header->ncmds; i++, cur += cur_seg_cmd->cmdsize) {
175188
cur_seg_cmd = (segment_command_t *)cur;
@@ -183,31 +196,32 @@ static void rebind_symbols_for_image(struct rebindings_entry *rebindings,
183196
dysymtab_cmd = (struct dysymtab_command*)cur_seg_cmd;
184197
}
185198
}
186-
199+
187200
if (!symtab_cmd || !dysymtab_cmd || !linkedit_segment ||
188201
!dysymtab_cmd->nindirectsyms) {
189202
return;
190203
}
191-
204+
192205
// Find base symbol/string table addresses
193206
uintptr_t linkedit_base = (uintptr_t)slide + linkedit_segment->vmaddr - linkedit_segment->fileoff;
194207
nlist_t *symtab = (nlist_t *)(linkedit_base + symtab_cmd->symoff);
195208
char *strtab = (char *)(linkedit_base + symtab_cmd->stroff);
196-
209+
197210
// Get indirect symbol table (array of uint32_t indices into symbol table)
198211
uint32_t *indirect_symtab = (uint32_t *)(linkedit_base + dysymtab_cmd->indirectsymoff);
199-
212+
200213
cur = (uintptr_t)header + sizeof(mach_header_t);
201214
for (uint i = 0; i < header->ncmds; i++, cur += cur_seg_cmd->cmdsize) {
202215
cur_seg_cmd = (segment_command_t *)cur;
203216
if (cur_seg_cmd->cmd == LC_SEGMENT_ARCH_DEPENDENT) {
204217
if (strcmp(cur_seg_cmd->segname, SEG_DATA) != 0 &&
205-
strcmp(cur_seg_cmd->segname, SEG_DATA_CONST) != 0) {
218+
strcmp(cur_seg_cmd->segname, SEG_DATA_CONST) != 0 &&
219+
strcmp(cur_seg_cmd->segname, SEG_AUTH_CONST) != 0) {
206220
continue;
207221
}
208222
for (uint j = 0; j < cur_seg_cmd->nsects; j++) {
209223
section_t *sect =
210-
(section_t *)(cur + sizeof(segment_command_t)) + j;
224+
(section_t *)(cur + sizeof(segment_command_t)) + j;
211225
if ((sect->flags & SECTION_TYPE) == S_LAZY_SYMBOL_POINTERS) {
212226
perform_rebinding_with_section(rebindings, sect, slide, symtab, strtab, indirect_symtab);
213227
}
@@ -221,21 +235,21 @@ static void rebind_symbols_for_image(struct rebindings_entry *rebindings,
221235

222236
static void _rebind_symbols_for_image(const struct mach_header *header,
223237
intptr_t slide) {
224-
rebind_symbols_for_image(_rebindings_head, header, slide);
238+
rebind_symbols_for_image(_rebindings_head, header, slide);
225239
}
226240

227241
int rebind_symbols_image(void *header,
228242
intptr_t slide,
229243
struct rebinding rebindings[],
230244
size_t rebindings_nel) {
231-
struct rebindings_entry *rebindings_head = NULL;
232-
int retval = prepend_rebindings(&rebindings_head, rebindings, rebindings_nel);
233-
rebind_symbols_for_image(rebindings_head, (const struct mach_header *) header, slide);
234-
if (rebindings_head) {
235-
free(rebindings_head->rebindings);
236-
}
237-
free(rebindings_head);
238-
return retval;
245+
struct rebindings_entry *rebindings_head = NULL;
246+
int retval = prepend_rebindings(&rebindings_head, rebindings, rebindings_nel);
247+
rebind_symbols_for_image(rebindings_head, (const struct mach_header *) header, slide);
248+
if (rebindings_head) {
249+
free(rebindings_head->rebindings);
250+
}
251+
free(rebindings_head);
252+
return retval;
239253
}
240254

241255
int rebind_symbols(struct rebinding rebindings[], size_t rebindings_nel) {

0 commit comments

Comments
 (0)