ruby-oci8 2.2.12 → 2.2.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/NEWS +26 -0
- data/docs/hanging-after-inactivity.md +1 -1
- data/ext/oci8/extconf.rb +1 -0
- data/ext/oci8/oci8.c +2 -2
- data/ext/oci8/oci8.h +6 -5
- data/ext/oci8/oci8lib.c +14 -22
- data/ext/oci8/oraconf.rb +4 -0
- data/ext/oci8/oradate.c +0 -11
- data/ext/oci8/plthook.h +7 -1
- data/ext/oci8/plthook_elf.c +422 -197
- data/ext/oci8/plthook_osx.c +725 -91
- data/ext/oci8/plthook_win32.c +39 -25
- data/lib/oci8/oracle_version.rb +9 -1
- data/lib/oci8/version.rb +1 -1
- data/lib/oci8.rb +2 -0
- data/test/test_metadata.rb +1 -0
- data/test/test_oranumber.rb +3 -1
- data/test/test_package_type.rb +10 -4
- metadata +3 -3
data/ext/oci8/plthook_osx.c
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
/* -*- indent-tabs-mode: nil -*-
|
2
2
|
*
|
3
|
-
* plthook_osx.c --
|
3
|
+
* plthook_osx.c -- implementation of plthook for OS X
|
4
4
|
*
|
5
5
|
* URL: https://github.com/kubo/plthook
|
6
6
|
*
|
7
7
|
* ------------------------------------------------------
|
8
8
|
*
|
9
|
-
* Copyright 2014 Kubo Takehiro <kubo@jiubao.org>
|
9
|
+
* Copyright 2014-2019 Kubo Takehiro <kubo@jiubao.org>
|
10
10
|
*
|
11
11
|
* Redistribution and use in source and binary forms, with or without modification, are
|
12
12
|
* permitted provided that the following conditions are met:
|
@@ -37,12 +37,24 @@
|
|
37
37
|
#include <stdarg.h>
|
38
38
|
#include <stdlib.h>
|
39
39
|
#include <string.h>
|
40
|
+
#include <unistd.h>
|
41
|
+
#include <inttypes.h>
|
40
42
|
#include <dlfcn.h>
|
43
|
+
#include <errno.h>
|
44
|
+
#include <mach/mach.h>
|
41
45
|
#include <mach-o/dyld.h>
|
46
|
+
#include <sys/mman.h>
|
47
|
+
#include <mach-o/fixup-chains.h>
|
42
48
|
#include "plthook.h"
|
43
49
|
|
50
|
+
#if !defined(__x86_64__)
|
51
|
+
#error Not on macOS intel
|
52
|
+
#endif
|
53
|
+
|
44
54
|
// #define PLTHOOK_DEBUG_CMD 1
|
45
55
|
// #define PLTHOOK_DEBUG_BIND 1
|
56
|
+
// #define PLTHOOK_DEBUG_FIXUPS 1
|
57
|
+
// #define PLTHOOK_DEBUG_ADDR 1
|
46
58
|
|
47
59
|
#ifdef PLTHOOK_DEBUG_CMD
|
48
60
|
#define DEBUG_CMD(...) fprintf(stderr, __VA_ARGS__)
|
@@ -50,16 +62,90 @@
|
|
50
62
|
#define DEBUG_CMD(...)
|
51
63
|
#endif
|
52
64
|
|
65
|
+
#ifdef PLTHOOK_DEBUG_FIXUPS
|
66
|
+
#define DEBUG_FIXUPS(...) fprintf(stderr, __VA_ARGS__)
|
67
|
+
#else
|
68
|
+
#define DEBUG_FIXUPS(...)
|
69
|
+
#endif
|
70
|
+
|
53
71
|
#ifdef PLTHOOK_DEBUG_BIND
|
54
72
|
#define DEBUG_BIND(...) fprintf(stderr, __VA_ARGS__)
|
55
73
|
#else
|
56
74
|
#define DEBUG_BIND(...)
|
57
75
|
#endif
|
58
76
|
|
59
|
-
#ifdef
|
60
|
-
#
|
61
|
-
|
62
|
-
#define
|
77
|
+
#ifdef PLTHOOK_DEBUG_ADDR
|
78
|
+
#include <mach/mach.h>
|
79
|
+
|
80
|
+
#define INHERIT_MAX_SIZE 11
|
81
|
+
static char *inherit_to_str(vm_inherit_t inherit, char *buf)
|
82
|
+
{
|
83
|
+
switch (inherit) {
|
84
|
+
case VM_INHERIT_SHARE: return "share";
|
85
|
+
case VM_INHERIT_COPY: return "copy";
|
86
|
+
case VM_INHERIT_NONE: return "none";
|
87
|
+
case VM_INHERIT_DONATE_COPY: return "donate_copy";
|
88
|
+
default:
|
89
|
+
sprintf(buf, "%d", inherit);
|
90
|
+
return buf;
|
91
|
+
}
|
92
|
+
}
|
93
|
+
|
94
|
+
#define BEHAVIOR_MAX_SIZE 16
|
95
|
+
static char *behavior_to_str(vm_behavior_t behavior, char *buf)
|
96
|
+
{
|
97
|
+
switch (behavior) {
|
98
|
+
case VM_BEHAVIOR_DEFAULT: return "default";
|
99
|
+
case VM_BEHAVIOR_RANDOM: return "random";
|
100
|
+
case VM_BEHAVIOR_SEQUENTIAL: return "sequential";
|
101
|
+
case VM_BEHAVIOR_RSEQNTL: return "rseqntl";
|
102
|
+
case VM_BEHAVIOR_WILLNEED: return "willneed";
|
103
|
+
case VM_BEHAVIOR_DONTNEED: return "dontneed";
|
104
|
+
case VM_BEHAVIOR_FREE: return "free";
|
105
|
+
case VM_BEHAVIOR_ZERO_WIRED_PAGES: return "zero";
|
106
|
+
case VM_BEHAVIOR_REUSABLE: return "reusable";
|
107
|
+
case VM_BEHAVIOR_REUSE: return "reuse";
|
108
|
+
case VM_BEHAVIOR_CAN_REUSE: return "can";
|
109
|
+
case VM_BEHAVIOR_PAGEOUT: return "pageout";
|
110
|
+
default:
|
111
|
+
sprintf(buf, "%d", behavior);
|
112
|
+
return buf;
|
113
|
+
}
|
114
|
+
}
|
115
|
+
|
116
|
+
static void dump_maps(const char *image_name)
|
117
|
+
{
|
118
|
+
mach_port_t task = mach_task_self();
|
119
|
+
vm_region_basic_info_data_64_t info;
|
120
|
+
mach_msg_type_number_t info_count = VM_REGION_BASIC_INFO_COUNT_64;
|
121
|
+
memory_object_name_t object = 0;
|
122
|
+
vm_address_t addr = 0;
|
123
|
+
vm_size_t size;
|
124
|
+
char inherit_buf[INHERIT_MAX_SIZE + 1];
|
125
|
+
char behavior_buf[BEHAVIOR_MAX_SIZE + 1];
|
126
|
+
|
127
|
+
fprintf(stderr, "MEMORY MAP(%s)\n", image_name);
|
128
|
+
fprintf(stderr, " start address end address protection max_protection inherit shared reserved offset behavior user_wired_count\n");
|
129
|
+
while (vm_region_64(task, &addr, &size, VM_REGION_BASIC_INFO_64, (vm_region_info_t)&info, &info_count, &object) == KERN_SUCCESS) {
|
130
|
+
fprintf(stderr, " %016lx-%016lx %c%c%c(%08x) %c%c%c(%08x) %-*s %c %c %08llx %-*s %u\n",
|
131
|
+
addr, addr + size,
|
132
|
+
(info.protection & VM_PROT_READ) ? 'r' : '-',
|
133
|
+
(info.protection & VM_PROT_WRITE) ? 'w' : '-',
|
134
|
+
(info.protection & VM_PROT_EXECUTE) ? 'x' : '-',
|
135
|
+
info.protection,
|
136
|
+
(info.max_protection & VM_PROT_READ) ? 'r' : '-',
|
137
|
+
(info.max_protection & VM_PROT_WRITE) ? 'w' : '-',
|
138
|
+
(info.max_protection & VM_PROT_EXECUTE) ? 'x' : '-',
|
139
|
+
info.max_protection,
|
140
|
+
INHERIT_MAX_SIZE, inherit_to_str(info.inheritance, inherit_buf),
|
141
|
+
info.shared ? 'Y' : 'N',
|
142
|
+
info.reserved ? 'Y' : 'N',
|
143
|
+
info.offset,
|
144
|
+
BEHAVIOR_MAX_SIZE, behavior_to_str(info.behavior, behavior_buf),
|
145
|
+
info.user_wired_count);
|
146
|
+
addr += size;
|
147
|
+
}
|
148
|
+
}
|
63
149
|
#endif
|
64
150
|
|
65
151
|
typedef struct {
|
@@ -67,16 +153,40 @@ typedef struct {
|
|
67
153
|
void **addr;
|
68
154
|
} bind_address_t;
|
69
155
|
|
156
|
+
typedef struct mem_prot {
|
157
|
+
size_t start;
|
158
|
+
size_t end;
|
159
|
+
int prot;
|
160
|
+
} mem_prot_t;
|
161
|
+
|
162
|
+
#define NUM_MEM_PROT 100
|
163
|
+
|
70
164
|
struct plthook {
|
71
165
|
unsigned int num_entries;
|
72
|
-
|
166
|
+
mem_prot_t mem_prot[NUM_MEM_PROT];
|
167
|
+
bind_address_t entries[1]; /* This must be the last. */
|
73
168
|
};
|
74
169
|
|
75
|
-
|
76
|
-
|
170
|
+
#define MAX_SEGMENTS 8
|
171
|
+
|
172
|
+
typedef struct {
|
173
|
+
plthook_t *plthook;
|
174
|
+
intptr_t slide;
|
175
|
+
int num_segments;
|
176
|
+
int linkedit_segment_idx;
|
177
|
+
struct segment_command_64 *segments[MAX_SEGMENTS];
|
178
|
+
struct linkedit_data_command *chained_fixups;
|
179
|
+
size_t got_addr;
|
180
|
+
} data_t;
|
181
|
+
|
182
|
+
static int plthook_open_real(plthook_t **plthook_out, uint32_t image_idx, const struct mach_header *mh, const char *image_name);
|
183
|
+
static unsigned int set_bind_addrs(data_t *d, uint32_t lazy_bind_off, uint32_t lazy_bind_size);
|
184
|
+
static void set_bind_addr(data_t *d, unsigned int *idx, const char *sym_name, int seg_index, int seg_offset);
|
185
|
+
static int read_chained_fixups(data_t *d, const struct mach_header *mh, const char *image_name);
|
186
|
+
static int set_mem_prot(plthook_t *plthook);
|
187
|
+
static int get_mem_prot(plthook_t *plthook, void *addr);
|
77
188
|
|
78
189
|
static void set_errmsg(const char *fmt, ...) __attribute__((__format__ (__printf__, 1, 2)));
|
79
|
-
static void set_bind_addr(unsigned int *idx, plthook_t *plthook, const uint8_t *base, const char *sym_name, int seg_index, uint64_t seg_offset, struct segment_command_ **segments);
|
80
190
|
|
81
191
|
static uint64_t uleb128(const uint8_t **p)
|
82
192
|
{
|
@@ -113,33 +223,40 @@ static char errmsg[512];
|
|
113
223
|
|
114
224
|
int plthook_open(plthook_t **plthook_out, const char *filename)
|
115
225
|
{
|
116
|
-
|
226
|
+
size_t namelen;
|
227
|
+
uint32_t cnt;
|
228
|
+
uint32_t idx;
|
117
229
|
|
118
|
-
if (filename
|
119
|
-
|
230
|
+
if (filename == NULL) {
|
231
|
+
return plthook_open_real(plthook_out, 0, NULL, NULL);
|
232
|
+
}
|
233
|
+
cnt = _dyld_image_count();
|
234
|
+
namelen = strlen(filename);
|
235
|
+
namelen = strlen(filename);
|
236
|
+
cnt = _dyld_image_count();
|
120
237
|
|
121
|
-
|
122
|
-
|
123
|
-
|
238
|
+
for (idx = 0; idx < cnt; idx++) {
|
239
|
+
const char *image_name = _dyld_get_image_name(idx);
|
240
|
+
size_t offset = 0;
|
124
241
|
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
}
|
135
|
-
}
|
136
|
-
if (strcmp(image_name + offset, filename) == 0) {
|
137
|
-
break;
|
242
|
+
if (image_name == NULL) {
|
243
|
+
*plthook_out = NULL;
|
244
|
+
set_errmsg("Cannot find file at image index %u", idx);
|
245
|
+
return PLTHOOK_INTERNAL_ERROR;
|
246
|
+
}
|
247
|
+
if (*filename != '/') {
|
248
|
+
size_t image_name_len = strlen(image_name);
|
249
|
+
if (image_name_len > namelen) {
|
250
|
+
offset = image_name_len - namelen;
|
138
251
|
}
|
139
|
-
|
252
|
+
}
|
253
|
+
if (strcmp(image_name + offset, filename) == 0) {
|
254
|
+
return plthook_open_real(plthook_out, idx, NULL, image_name);
|
140
255
|
}
|
141
256
|
}
|
142
|
-
|
257
|
+
*plthook_out = NULL;
|
258
|
+
set_errmsg("Cannot find file: %s", filename);
|
259
|
+
return PLTHOOK_FILE_NOT_FOUND;
|
143
260
|
}
|
144
261
|
|
145
262
|
int plthook_open_by_handle(plthook_t **plthook_out, void *hndl)
|
@@ -148,7 +265,8 @@ int plthook_open_by_handle(plthook_t **plthook_out, void *hndl)
|
|
148
265
|
RTLD_LAZY | RTLD_NOLOAD,
|
149
266
|
RTLD_LAZY | RTLD_NOLOAD | RTLD_FIRST,
|
150
267
|
};
|
151
|
-
|
268
|
+
int flag_idx;
|
269
|
+
uint32_t cnt = _dyld_image_count();
|
152
270
|
#define NUM_FLAGS (sizeof(flags) / sizeof(flags[0]))
|
153
271
|
|
154
272
|
if (hndl == NULL) {
|
@@ -156,18 +274,18 @@ int plthook_open_by_handle(plthook_t **plthook_out, void *hndl)
|
|
156
274
|
return PLTHOOK_FILE_NOT_FOUND;
|
157
275
|
}
|
158
276
|
for (flag_idx = 0; flag_idx < NUM_FLAGS; flag_idx++) {
|
159
|
-
|
160
|
-
uint32_t idx = 0;
|
277
|
+
uint32_t idx;
|
161
278
|
|
162
|
-
|
279
|
+
for (idx = 0; idx < cnt; idx++) {
|
280
|
+
const char *image_name = idx ? _dyld_get_image_name(idx) : NULL;
|
163
281
|
void *handle = dlopen(image_name, flags[flag_idx]);
|
164
282
|
if (handle != NULL) {
|
165
283
|
dlclose(handle);
|
166
284
|
if (handle == hndl) {
|
167
|
-
return plthook_open_real(plthook_out,
|
285
|
+
return plthook_open_real(plthook_out, idx, NULL, image_name);
|
168
286
|
}
|
169
287
|
}
|
170
|
-
}
|
288
|
+
}
|
171
289
|
}
|
172
290
|
set_errmsg("Cannot find the image correspond to handle %p", hndl);
|
173
291
|
return PLTHOOK_FILE_NOT_FOUND;
|
@@ -176,43 +294,62 @@ int plthook_open_by_handle(plthook_t **plthook_out, void *hndl)
|
|
176
294
|
int plthook_open_by_address(plthook_t **plthook_out, void *address)
|
177
295
|
{
|
178
296
|
Dl_info dlinfo;
|
297
|
+
uint32_t idx = 0;
|
298
|
+
uint32_t cnt = _dyld_image_count();
|
179
299
|
|
180
300
|
if (!dladdr(address, &dlinfo)) {
|
181
301
|
*plthook_out = NULL;
|
182
302
|
set_errmsg("Cannot find address: %p", address);
|
183
303
|
return PLTHOOK_FILE_NOT_FOUND;
|
184
304
|
}
|
185
|
-
|
305
|
+
for (idx = 0; idx < cnt; idx++) {
|
306
|
+
if (dlinfo.dli_fbase == _dyld_get_image_header(idx)) {
|
307
|
+
return plthook_open_real(plthook_out, idx, dlinfo.dli_fbase, dlinfo.dli_fname);
|
308
|
+
}
|
309
|
+
}
|
310
|
+
set_errmsg("Cannot find the image index for base address: %p", dlinfo.dli_fbase);
|
311
|
+
return PLTHOOK_FILE_NOT_FOUND;
|
186
312
|
}
|
187
313
|
|
188
|
-
|
189
|
-
|
190
|
-
static int plthook_open_real(plthook_t **plthook_out, const struct mach_header *mh)
|
314
|
+
static int plthook_open_real(plthook_t **plthook_out, uint32_t image_idx, const struct mach_header *mh, const char *image_name)
|
191
315
|
{
|
192
316
|
struct load_command *cmd;
|
193
|
-
const uint8_t *base = (const uint8_t *)mh;
|
194
317
|
uint32_t lazy_bind_off = 0;
|
195
318
|
uint32_t lazy_bind_size = 0;
|
196
|
-
struct segment_command_ *segments[NUM_SEGMENTS];
|
197
|
-
int segment_idx = 0;
|
198
319
|
unsigned int nbind;
|
199
|
-
|
200
|
-
|
320
|
+
data_t data = {NULL,};
|
321
|
+
size_t size;
|
322
|
+
int i;
|
201
323
|
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
324
|
+
data.linkedit_segment_idx = -1;
|
325
|
+
data.slide = _dyld_get_image_vmaddr_slide(image_idx);
|
326
|
+
if (mh == NULL) {
|
327
|
+
mh = _dyld_get_image_header(image_idx);
|
328
|
+
}
|
329
|
+
if (image_name == NULL) {
|
330
|
+
image_name = _dyld_get_image_name(image_idx);
|
331
|
+
}
|
332
|
+
#if defined(PLTHOOK_DEBUG_CMD) || defined(PLTHOOK_DEBUG_ADDR)
|
333
|
+
fprintf(stderr, "mh=%"PRIxPTR" slide=%"PRIxPTR"\n", (uintptr_t)mh, data.slide);
|
334
|
+
#endif
|
335
|
+
#ifdef PLTHOOK_DEBUG_ADDR
|
336
|
+
dump_maps(image_name);
|
207
337
|
#endif
|
338
|
+
|
339
|
+
cmd = (struct load_command *)((size_t)mh + sizeof(struct mach_header_64));
|
340
|
+
DEBUG_CMD("CMD START\n");
|
208
341
|
for (i = 0; i < mh->ncmds; i++) {
|
209
342
|
struct dyld_info_command *dyld_info;
|
343
|
+
#ifdef PLTHOOK_DEBUG_CMD
|
210
344
|
struct segment_command *segment;
|
345
|
+
#endif
|
211
346
|
struct segment_command_64 *segment64;
|
212
347
|
|
213
348
|
switch (cmd->cmd) {
|
214
349
|
case LC_SEGMENT: /* 0x1 */
|
350
|
+
#ifdef PLTHOOK_DEBUG_CMD
|
215
351
|
segment = (struct segment_command *)cmd;
|
352
|
+
#endif
|
216
353
|
DEBUG_CMD("LC_SEGMENT\n"
|
217
354
|
" segname %s\n"
|
218
355
|
" vmaddr %8x vmsize %8x\n"
|
@@ -224,12 +361,6 @@ static int plthook_open_real(plthook_t **plthook_out, const struct mach_header *
|
|
224
361
|
segment->fileoff, segment->filesize,
|
225
362
|
segment->maxprot, segment->initprot,
|
226
363
|
segment->nsects, segment->flags);
|
227
|
-
if (strcmp(segment->segname, "__LINKEDIT") == 0) {
|
228
|
-
addrdiff = segment->vmaddr - segment->fileoff;
|
229
|
-
}
|
230
|
-
#ifndef __LP64__
|
231
|
-
segments[segment_idx++] = segment;
|
232
|
-
#endif
|
233
364
|
break;
|
234
365
|
case LC_SEGMENT_64: /* 0x19 */
|
235
366
|
segment64 = (struct segment_command_64 *)cmd;
|
@@ -245,11 +376,49 @@ static int plthook_open_real(plthook_t **plthook_out, const struct mach_header *
|
|
245
376
|
segment64->maxprot, segment64->initprot,
|
246
377
|
segment64->nsects, segment64->flags);
|
247
378
|
if (strcmp(segment64->segname, "__LINKEDIT") == 0) {
|
248
|
-
|
379
|
+
data.linkedit_segment_idx = data.num_segments;
|
249
380
|
}
|
250
|
-
|
251
|
-
|
252
|
-
|
381
|
+
if (strcmp(segment64->segname, "__DATA_CONST") == 0) {
|
382
|
+
struct section_64 *sec = (struct section_64 *)(segment64 + 1);
|
383
|
+
uint32_t i;
|
384
|
+
for (i = 0; i < segment64->nsects; i++) {
|
385
|
+
DEBUG_CMD(" section_64 (%u)\n"
|
386
|
+
" sectname %s\n"
|
387
|
+
" segname %s\n"
|
388
|
+
" addr 0x%llx\n"
|
389
|
+
" size 0x%llx\n"
|
390
|
+
" offset 0x%x\n"
|
391
|
+
" align 0x%x\n"
|
392
|
+
" reloff 0x%x\n"
|
393
|
+
" nreloc %d\n"
|
394
|
+
" flags 0x%x\n"
|
395
|
+
" reserved1 %d\n"
|
396
|
+
" reserved2 %d\n"
|
397
|
+
" reserved3 %d\n",
|
398
|
+
i,
|
399
|
+
sec->sectname,
|
400
|
+
sec->segname,
|
401
|
+
sec->addr,
|
402
|
+
sec->size,
|
403
|
+
sec->offset,
|
404
|
+
sec->align,
|
405
|
+
sec->reloff,
|
406
|
+
sec->nreloc,
|
407
|
+
sec->flags,
|
408
|
+
sec->reserved1,
|
409
|
+
sec->reserved2,
|
410
|
+
sec->reserved3);
|
411
|
+
if (strcmp(sec->segname, "__DATA_CONST") == 0 && strcmp(sec->sectname, "__got") == 0) {
|
412
|
+
data.got_addr = sec->addr + data.slide;
|
413
|
+
}
|
414
|
+
sec++;
|
415
|
+
}
|
416
|
+
}
|
417
|
+
if (data.num_segments == MAX_SEGMENTS) {
|
418
|
+
set_errmsg("Too many segments: %s", image_name);
|
419
|
+
return PLTHOOK_INTERNAL_ERROR;
|
420
|
+
}
|
421
|
+
data.segments[data.num_segments++] = segment64;
|
253
422
|
break;
|
254
423
|
case LC_DYLD_INFO_ONLY: /* (0x22|LC_REQ_DYLD) */
|
255
424
|
dyld_info= (struct dyld_info_command *)cmd;
|
@@ -289,6 +458,9 @@ static int plthook_open_real(plthook_t **plthook_out, const struct mach_header *
|
|
289
458
|
case LC_UUID: /* 0x1b */
|
290
459
|
DEBUG_CMD("LC_UUID\n");
|
291
460
|
break;
|
461
|
+
case LC_CODE_SIGNATURE: /* 0x1d */
|
462
|
+
DEBUG_CMD("LC_CODE_SIGNATURE\n");
|
463
|
+
break;
|
292
464
|
case LC_VERSION_MIN_MACOSX: /* 0x24 */
|
293
465
|
DEBUG_CMD("LC_VERSION_MIN_MACOSX\n");
|
294
466
|
break;
|
@@ -307,41 +479,70 @@ static int plthook_open_real(plthook_t **plthook_out, const struct mach_header *
|
|
307
479
|
case LC_DYLIB_CODE_SIGN_DRS: /* 0x2B */
|
308
480
|
DEBUG_CMD("LC_DYLIB_CODE_SIGN_DRS\n");
|
309
481
|
break;
|
482
|
+
case LC_BUILD_VERSION: /* 0x32 */
|
483
|
+
DEBUG_CMD("LC_BUILD_VERSION\n");
|
484
|
+
break;
|
485
|
+
case LC_DYLD_EXPORTS_TRIE: /* (0x33|LC_REQ_DYLD) */
|
486
|
+
DEBUG_CMD("LC_DYLD_EXPORTS_TRIE\n");
|
487
|
+
break;
|
488
|
+
case LC_DYLD_CHAINED_FIXUPS: /* (0x34|LC_REQ_DYLD) */
|
489
|
+
data.chained_fixups = (struct linkedit_data_command *)cmd;
|
490
|
+
DEBUG_CMD("LC_DYLD_CHAINED_FIXUPS\n"
|
491
|
+
" cmdsize %u\n"
|
492
|
+
" dataoff %u (0x%x)\n"
|
493
|
+
" datasize %u\n",
|
494
|
+
data.chained_fixups->cmdsize,
|
495
|
+
data.chained_fixups->dataoff,
|
496
|
+
data.chained_fixups->dataoff,
|
497
|
+
data.chained_fixups->datasize);
|
498
|
+
break;
|
310
499
|
default:
|
311
500
|
DEBUG_CMD("LC_? (0x%x)\n", cmd->cmd);
|
312
501
|
}
|
313
502
|
cmd = (struct load_command *)((size_t)cmd + cmd->cmdsize);
|
314
503
|
}
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
504
|
+
DEBUG_CMD("CMD END\n");
|
505
|
+
if (data.linkedit_segment_idx == -1) {
|
506
|
+
set_errmsg("Cannot find the linkedit segment: %s", image_name);
|
507
|
+
return PLTHOOK_INVALID_FILE_FORMAT;
|
508
|
+
}
|
509
|
+
if (data.chained_fixups != NULL) {
|
510
|
+
int rv = read_chained_fixups(&data, mh, image_name);
|
511
|
+
if (rv != 0) {
|
512
|
+
return rv;
|
513
|
+
}
|
514
|
+
} else {
|
515
|
+
nbind = set_bind_addrs(&data, lazy_bind_off, lazy_bind_size);
|
516
|
+
size = offsetof(plthook_t, entries) + sizeof(bind_address_t) * nbind;
|
517
|
+
data.plthook = (plthook_t*)calloc(1, size);
|
518
|
+
if (data.plthook == NULL) {
|
519
|
+
set_errmsg("failed to allocate memory: %" PRIuPTR " bytes", size);
|
520
|
+
return PLTHOOK_OUT_OF_MEMORY;
|
521
|
+
}
|
522
|
+
data.plthook->num_entries = nbind;
|
523
|
+
set_bind_addrs(&data, lazy_bind_off, lazy_bind_size);
|
524
|
+
}
|
525
|
+
set_mem_prot(data.plthook);
|
319
526
|
|
527
|
+
*plthook_out = data.plthook;
|
320
528
|
return 0;
|
321
529
|
}
|
322
530
|
|
323
|
-
static unsigned int
|
531
|
+
static unsigned int set_bind_addrs(data_t *data, uint32_t lazy_bind_off, uint32_t lazy_bind_size)
|
324
532
|
{
|
325
|
-
|
533
|
+
struct segment_command_64 *linkedit = data->segments[data->linkedit_segment_idx];
|
534
|
+
const uint8_t *ptr = (uint8_t*)(linkedit->vmaddr - linkedit->fileoff + data->slide + lazy_bind_off);
|
326
535
|
const uint8_t *end = ptr + lazy_bind_size;
|
327
536
|
const char *sym_name;
|
328
537
|
int seg_index = 0;
|
329
538
|
uint64_t seg_offset = 0;
|
330
|
-
|
331
|
-
unsigned int idx;
|
332
|
-
DEBUG_BIND("get_bind_addr(%p, 0x%x, 0x%x", base, lazy_bind_off, lazy_bind_size);
|
333
|
-
for (idx = 0; segments[idx] != NULL; idx++) {
|
334
|
-
DEBUG_BIND(", [%s]", segments[idx]->segname);
|
335
|
-
}
|
336
|
-
DEBUG_BIND(")\n");
|
539
|
+
int count, skip;
|
540
|
+
unsigned int idx = 0;
|
337
541
|
|
338
|
-
idx = 0;
|
339
542
|
while (ptr < end) {
|
340
543
|
uint8_t op = *ptr & BIND_OPCODE_MASK;
|
341
544
|
uint8_t imm = *ptr & BIND_IMMEDIATE_MASK;
|
342
|
-
|
343
|
-
int64_t slebval;
|
344
|
-
uint64_t i;
|
545
|
+
int i;
|
345
546
|
|
346
547
|
DEBUG_BIND("0x%02x: ", *ptr);
|
347
548
|
ptr++;
|
@@ -353,8 +554,11 @@ static unsigned int get_bind_addr(plthook_t *plthook, const uint8_t *base, uint3
|
|
353
554
|
DEBUG_BIND("BIND_OPCODE_SET_DYLIB_ORDINAL_IMM: ordinal = %u\n", imm);
|
354
555
|
break;
|
355
556
|
case BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB:
|
356
|
-
|
357
|
-
DEBUG_BIND("BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB: ordinal = %llu\n",
|
557
|
+
#ifdef PLTHOOK_DEBUG_BIND
|
558
|
+
DEBUG_BIND("BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB: ordinal = %llu\n", uleb128(&ptr));
|
559
|
+
#else
|
560
|
+
uleb128(&ptr);
|
561
|
+
#endif
|
358
562
|
break;
|
359
563
|
case BIND_OPCODE_SET_DYLIB_SPECIAL_IMM:
|
360
564
|
if (imm == 0) {
|
@@ -371,8 +575,11 @@ static unsigned int get_bind_addr(plthook_t *plthook, const uint8_t *base, uint3
|
|
371
575
|
DEBUG_BIND("BIND_OPCODE_SET_TYPE_IMM: type = %u\n", imm);
|
372
576
|
break;
|
373
577
|
case BIND_OPCODE_SET_ADDEND_SLEB:
|
374
|
-
|
375
|
-
DEBUG_BIND("BIND_OPCODE_SET_ADDEND_SLEB: ordinal = %lld\n",
|
578
|
+
#ifdef PLTHOOK_DEBUG_BIND
|
579
|
+
DEBUG_BIND("BIND_OPCODE_SET_ADDEND_SLEB: ordinal = %lld\n", sleb128(&ptr));
|
580
|
+
#else
|
581
|
+
sleb128(&ptr);
|
582
|
+
#endif
|
376
583
|
break;
|
377
584
|
case BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB:
|
378
585
|
seg_index = imm;
|
@@ -384,7 +591,7 @@ static unsigned int get_bind_addr(plthook_t *plthook, const uint8_t *base, uint3
|
|
384
591
|
DEBUG_BIND("BIND_OPCODE_ADD_ADDR_ULEB: seg_offset = 0x%llx\n", seg_offset);
|
385
592
|
break;
|
386
593
|
case BIND_OPCODE_DO_BIND:
|
387
|
-
set_bind_addr(&idx,
|
594
|
+
set_bind_addr(data, &idx, sym_name, seg_index, seg_offset);
|
388
595
|
DEBUG_BIND("BIND_OPCODE_DO_BIND\n");
|
389
596
|
break;
|
390
597
|
case BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB:
|
@@ -392,7 +599,7 @@ static unsigned int get_bind_addr(plthook_t *plthook, const uint8_t *base, uint3
|
|
392
599
|
DEBUG_BIND("BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB: seg_offset = 0x%llx\n", seg_offset);
|
393
600
|
break;
|
394
601
|
case BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED:
|
395
|
-
set_bind_addr(&idx,
|
602
|
+
set_bind_addr(data, &idx, sym_name, seg_index, seg_offset);
|
396
603
|
seg_offset += imm * sizeof(void *);
|
397
604
|
DEBUG_BIND("BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED\n");
|
398
605
|
break;
|
@@ -400,7 +607,7 @@ static unsigned int get_bind_addr(plthook_t *plthook, const uint8_t *base, uint3
|
|
400
607
|
count = uleb128(&ptr);
|
401
608
|
skip = uleb128(&ptr);
|
402
609
|
for (i = 0; i < count; i++) {
|
403
|
-
set_bind_addr(&idx,
|
610
|
+
set_bind_addr(data, &idx, sym_name, seg_index, seg_offset);
|
404
611
|
seg_offset += skip;
|
405
612
|
}
|
406
613
|
DEBUG_BIND("BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB\n");
|
@@ -410,17 +617,425 @@ static unsigned int get_bind_addr(plthook_t *plthook, const uint8_t *base, uint3
|
|
410
617
|
return idx;
|
411
618
|
}
|
412
619
|
|
413
|
-
static void set_bind_addr(
|
620
|
+
static void set_bind_addr(data_t *data, unsigned int *idx, const char *sym_name, int seg_index, int seg_offset)
|
414
621
|
{
|
415
|
-
if (plthook != NULL) {
|
416
|
-
|
417
|
-
plthook->entries[*idx].name = sym_name;
|
418
|
-
plthook->entries[*idx].addr = (void**)(
|
622
|
+
if (data->plthook != NULL) {
|
623
|
+
size_t vmaddr = data->segments[seg_index]->vmaddr;
|
624
|
+
data->plthook->entries[*idx].name = sym_name;
|
625
|
+
data->plthook->entries[*idx].addr = (void**)(vmaddr + data->slide + seg_offset);
|
419
626
|
}
|
420
627
|
(*idx)++;
|
421
628
|
}
|
422
629
|
|
630
|
+
static int read_chained_fixups(data_t *d, const struct mach_header *mh, const char *image_name)
|
631
|
+
{
|
632
|
+
const uint8_t *ptr = (const uint8_t *)mh + d->chained_fixups->dataoff;
|
633
|
+
const uint8_t *end = ptr + d->chained_fixups->datasize;
|
634
|
+
const struct dyld_chained_fixups_header *header = (const struct dyld_chained_fixups_header *)ptr;
|
635
|
+
const struct dyld_chained_import *import = (const struct dyld_chained_import *)(ptr + header->imports_offset);
|
636
|
+
const struct dyld_chained_import_addend *import_addend = (const struct dyld_chained_import_addend *)(ptr + header->imports_offset);
|
637
|
+
const struct dyld_chained_import_addend64 *import_addend64 = (const struct dyld_chained_import_addend64 *)(ptr + header->imports_offset);
|
638
|
+
const char *symbol_pool = (const char*)ptr + header->symbols_offset;
|
639
|
+
int rv = PLTHOOK_INTERNAL_ERROR;
|
640
|
+
size_t size;
|
641
|
+
uint32_t i;
|
642
|
+
#ifdef PLTHOOK_DEBUG_FIXUPS
|
643
|
+
const struct dyld_chained_starts_in_image *starts = (const struct dyld_chained_starts_in_image *)(ptr + header->starts_offset);
|
644
|
+
FILE *fp = NULL;
|
645
|
+
#endif
|
646
|
+
if (d->got_addr == 0) {
|
647
|
+
set_errmsg("__got section is not found in %s", image_name);
|
648
|
+
rv = PLTHOOK_INVALID_FILE_FORMAT;
|
649
|
+
goto cleanup;
|
650
|
+
}
|
651
|
+
|
652
|
+
DEBUG_FIXUPS("dyld_chained_fixups_header\n"
|
653
|
+
" fixups_version %u\n"
|
654
|
+
" starts_offset %u\n"
|
655
|
+
" imports_offset %u\n"
|
656
|
+
" symbols_offset %u\n"
|
657
|
+
" imports_count %u\n"
|
658
|
+
" imports_format %u\n"
|
659
|
+
" symbols_format %u\n",
|
660
|
+
header->fixups_version,
|
661
|
+
header->starts_offset,
|
662
|
+
header->imports_offset,
|
663
|
+
header->symbols_offset,
|
664
|
+
header->imports_count,
|
665
|
+
header->imports_format,
|
666
|
+
header->symbols_format);
|
667
|
+
if (header->fixups_version != 0) {
|
668
|
+
set_errmsg("unknown chained fixups version %u", header->fixups_version);
|
669
|
+
rv = PLTHOOK_INVALID_FILE_FORMAT;
|
670
|
+
goto cleanup;
|
671
|
+
}
|
672
|
+
|
673
|
+
size = offsetof(plthook_t, entries) + sizeof(bind_address_t) * header->imports_count;
|
674
|
+
d->plthook = (plthook_t*)calloc(1, size);
|
675
|
+
if (d->plthook == NULL) {
|
676
|
+
set_errmsg("failed to allocate memory: %" PRIuPTR " bytes", size);
|
677
|
+
rv = PLTHOOK_OUT_OF_MEMORY;
|
678
|
+
goto cleanup;
|
679
|
+
}
|
680
|
+
d->plthook->num_entries = header->imports_count;
|
681
|
+
|
682
|
+
switch (header->imports_format) {
|
683
|
+
case DYLD_CHAINED_IMPORT:
|
684
|
+
DEBUG_FIXUPS("dyld_chained_import\n");
|
685
|
+
break;
|
686
|
+
case DYLD_CHAINED_IMPORT_ADDEND:
|
687
|
+
DEBUG_FIXUPS("dyld_chained_import_addend\n");
|
688
|
+
break;
|
689
|
+
case DYLD_CHAINED_IMPORT_ADDEND64:
|
690
|
+
DEBUG_FIXUPS("dyld_chained_import_addend64\n");
|
691
|
+
break;
|
692
|
+
default:
|
693
|
+
set_errmsg("unknown imports format %u", header->imports_format);
|
694
|
+
rv = PLTHOOK_INVALID_FILE_FORMAT;
|
695
|
+
goto cleanup;
|
696
|
+
}
|
697
|
+
|
698
|
+
for (i = 0; i < header->imports_count; i++) {
|
699
|
+
struct dyld_chained_import_addend64 imp;
|
700
|
+
switch (header->imports_format) {
|
701
|
+
case DYLD_CHAINED_IMPORT:
|
702
|
+
imp.lib_ordinal = import[i].lib_ordinal;
|
703
|
+
imp.weak_import = import[i].weak_import;
|
704
|
+
imp.name_offset = import[i].name_offset;
|
705
|
+
imp.addend = 0;
|
706
|
+
break;
|
707
|
+
case DYLD_CHAINED_IMPORT_ADDEND:
|
708
|
+
imp.lib_ordinal = import_addend[i].lib_ordinal;
|
709
|
+
imp.weak_import = import_addend[i].weak_import;
|
710
|
+
imp.name_offset = import_addend[i].name_offset;
|
711
|
+
imp.addend = import_addend[i].addend;
|
712
|
+
break;
|
713
|
+
case DYLD_CHAINED_IMPORT_ADDEND64:
|
714
|
+
imp = import_addend64[i];
|
715
|
+
break;
|
716
|
+
}
|
717
|
+
const char *name = symbol_pool + imp.name_offset;
|
718
|
+
if (name > (const char*)end) {
|
719
|
+
DEBUG_FIXUPS(" lib_ordinal %u, weak_import %u, name_offset %u, addend %llu\n",
|
720
|
+
imp.lib_ordinal, imp.weak_import, imp.name_offset, imp.addend);
|
721
|
+
set_errmsg("invalid symbol name address");
|
722
|
+
rv = PLTHOOK_INVALID_FILE_FORMAT;
|
723
|
+
goto cleanup;
|
724
|
+
}
|
725
|
+
DEBUG_FIXUPS(" lib_ordinal %u, weak_import %u, name_offset %u (%s), addend %llu\n",
|
726
|
+
imp.lib_ordinal, imp.weak_import, imp.name_offset, name, imp.addend);
|
727
|
+
d->plthook->entries[i].name = name;
|
728
|
+
d->plthook->entries[i].addr = (void**)(d->got_addr + i * sizeof(void*));
|
729
|
+
}
|
730
|
+
|
731
|
+
#ifdef PLTHOOK_DEBUG_FIXUPS
|
732
|
+
fp = fopen(image_name, "r");
|
733
|
+
if (fp == NULL) {
|
734
|
+
set_errmsg("failed to open file %s (error: %s)", image_name, strerror(errno));
|
735
|
+
rv = PLTHOOK_FILE_NOT_FOUND;
|
736
|
+
goto cleanup;
|
737
|
+
}
|
738
|
+
|
739
|
+
DEBUG_FIXUPS("dyld_chained_starts_in_image\n"
|
740
|
+
" seg_count %u\n",
|
741
|
+
starts->seg_count);
|
742
|
+
for (i = 0; i < starts->seg_count; i++) {
|
743
|
+
DEBUG_FIXUPS(" seg_info_offset[%u] %u\n",
|
744
|
+
i, starts->seg_info_offset[i]);
|
745
|
+
if (starts->seg_info_offset[i] == 0) {
|
746
|
+
continue;
|
747
|
+
}
|
748
|
+
const struct dyld_chained_starts_in_segment* seg = (const struct dyld_chained_starts_in_segment*)((char*)starts + starts->seg_info_offset[i]);
|
749
|
+
uint16_t j;
|
750
|
+
DEBUG_FIXUPS(" dyld_chained_starts_in_segment\n"
|
751
|
+
" size %u\n"
|
752
|
+
" page_size 0x%x\n"
|
753
|
+
" pointer_format %u\n"
|
754
|
+
" segment_offset %llu (0x%llx)\n"
|
755
|
+
" max_valid_pointer %u\n"
|
756
|
+
" page_count %u\n",
|
757
|
+
seg->size, seg->page_size, seg->pointer_format, seg->segment_offset, seg->segment_offset, seg->max_valid_pointer, seg->page_count);
|
758
|
+
for (j = 0; j < seg->page_count; j++) {
|
759
|
+
uint16_t index = j;
|
760
|
+
uint16_t break_loop = 1;
|
761
|
+
off_t offset;
|
762
|
+
|
763
|
+
if (seg->page_start[j] == DYLD_CHAINED_PTR_START_NONE) {
|
764
|
+
DEBUG_FIXUPS(" page_start[%u] DYLD_CHAINED_PTR_START_NONE\n", j);
|
765
|
+
continue;
|
766
|
+
}
|
767
|
+
if (seg->page_start[j] & DYLD_CHAINED_PTR_START_MULTI) {
|
768
|
+
index = seg->page_start[j] & ~DYLD_CHAINED_PTR_START_MULTI;
|
769
|
+
DEBUG_FIXUPS(" page_start[%u] (DYLD_CHAINED_PTR_START_MULTI | %u)\n", j, index);
|
770
|
+
break_loop = 0;
|
771
|
+
}
|
772
|
+
while (1) {
|
773
|
+
if (index != j) {
|
774
|
+
DEBUG_FIXUPS(" page_start[%u] %u\n", index, seg->page_start[index]);
|
775
|
+
}
|
776
|
+
offset = seg->segment_offset + j * seg->page_size + (seg->page_start[index] & ~DYLD_CHAINED_PTR_START_MULTI);
|
777
|
+
switch (seg->pointer_format) {
|
778
|
+
case DYLD_CHAINED_PTR_64_OFFSET: {
|
779
|
+
union {
|
780
|
+
struct dyld_chained_ptr_64_rebase rebase;
|
781
|
+
struct dyld_chained_ptr_64_bind bind;
|
782
|
+
} buf;
|
783
|
+
|
784
|
+
do {
|
785
|
+
if (fseeko(fp, offset, SEEK_SET) != 0) {
|
786
|
+
set_errmsg("failed to seek to %lld in %s", offset, image_name);
|
787
|
+
rv = PLTHOOK_INVALID_FILE_FORMAT;
|
788
|
+
goto cleanup;
|
789
|
+
}
|
790
|
+
if (fread(&buf, sizeof(buf), 1, fp) != 1) {
|
791
|
+
set_errmsg("failed to read fixup chain from %s", image_name);
|
792
|
+
rv = PLTHOOK_INVALID_FILE_FORMAT;
|
793
|
+
goto cleanup;
|
794
|
+
}
|
795
|
+
if (buf.rebase.bind) {
|
796
|
+
DEBUG_FIXUPS(" dyld_chained_ptr_64_bind\n"
|
797
|
+
" ordinal %d\n"
|
798
|
+
" addend %d\n"
|
799
|
+
" reserved %d\n"
|
800
|
+
" next %d\n"
|
801
|
+
" bind %d\n",
|
802
|
+
buf.bind.ordinal,
|
803
|
+
buf.bind.addend,
|
804
|
+
buf.bind.reserved,
|
805
|
+
buf.bind.next,
|
806
|
+
buf.bind.bind);
|
807
|
+
} else {
|
808
|
+
DEBUG_FIXUPS(" dyld_chained_ptr_64_rebase\n"
|
809
|
+
" target %llu\n"
|
810
|
+
" high8 %d\n"
|
811
|
+
" reserved %d\n"
|
812
|
+
" next %d\n"
|
813
|
+
" bind %d\n",
|
814
|
+
buf.rebase.target,
|
815
|
+
buf.rebase.high8,
|
816
|
+
buf.rebase.reserved,
|
817
|
+
buf.rebase.next,
|
818
|
+
buf.rebase.bind);
|
819
|
+
}
|
820
|
+
offset += buf.bind.next * 4;
|
821
|
+
} while (buf.bind.next != 0);
|
822
|
+
break;
|
823
|
+
}
|
824
|
+
case DYLD_CHAINED_PTR_ARM64E:
|
825
|
+
case DYLD_CHAINED_PTR_ARM64E_KERNEL:
|
826
|
+
case DYLD_CHAINED_PTR_ARM64E_USERLAND:
|
827
|
+
case DYLD_CHAINED_PTR_ARM64E_USERLAND24: {
|
828
|
+
// The following code isn't tested.
|
829
|
+
union {
|
830
|
+
struct dyld_chained_ptr_arm64e_rebase rebase;
|
831
|
+
struct dyld_chained_ptr_arm64e_bind bind;
|
832
|
+
struct dyld_chained_ptr_arm64e_bind24 bind24;
|
833
|
+
struct dyld_chained_ptr_arm64e_auth_rebase auth_rebase;
|
834
|
+
struct dyld_chained_ptr_arm64e_auth_bind auth_bind;
|
835
|
+
struct dyld_chained_ptr_arm64e_auth_bind24 auth_bind24;
|
836
|
+
} buf;
|
837
|
+
|
838
|
+
do {
|
839
|
+
if (fseeko(fp, offset, SEEK_SET) != 0) {
|
840
|
+
set_errmsg("failed to seek to %lld in %s", offset, image_name);
|
841
|
+
rv = PLTHOOK_INVALID_FILE_FORMAT;
|
842
|
+
goto cleanup;
|
843
|
+
}
|
844
|
+
if (fread(&buf, sizeof(buf), 1, fp) != 1) {
|
845
|
+
set_errmsg("failed to read fixup chain from %s", image_name);
|
846
|
+
rv = PLTHOOK_INVALID_FILE_FORMAT;
|
847
|
+
goto cleanup;
|
848
|
+
}
|
849
|
+
if (!buf.rebase.auth) {
|
850
|
+
if (!buf.rebase.bind) {
|
851
|
+
DEBUG_FIXUPS(" dyld_chained_ptr_arm64e_rebase\n"
|
852
|
+
" target %llu\n"
|
853
|
+
" high8 %d\n"
|
854
|
+
" next %d\n"
|
855
|
+
" bind %d\n" // == 0
|
856
|
+
" auth %d\n", // == 0
|
857
|
+
buf.rebase.target,
|
858
|
+
buf.rebase.high8,
|
859
|
+
buf.rebase.next,
|
860
|
+
buf.rebase.bind,
|
861
|
+
buf.rebase.auth);
|
862
|
+
} else if (seg->pointer_format != DYLD_CHAINED_PTR_ARM64E_USERLAND24) {
|
863
|
+
DEBUG_FIXUPS(" dyld_chained_ptr_arm64e_bind\n"
|
864
|
+
" ordinal %d\n"
|
865
|
+
" zero %d\n"
|
866
|
+
" addend %d\n"
|
867
|
+
" next %d\n"
|
868
|
+
" bind %d\n" // == 1
|
869
|
+
" auth %d\n", // == 0
|
870
|
+
buf.bind.ordinal,
|
871
|
+
buf.bind.zero,
|
872
|
+
buf.bind.addend,
|
873
|
+
buf.bind.next,
|
874
|
+
buf.bind.bind,
|
875
|
+
buf.bind.auth);
|
876
|
+
} else {
|
877
|
+
DEBUG_FIXUPS(" dyld_chained_ptr_arm64e_bind24\n"
|
878
|
+
" ordinal %d\n"
|
879
|
+
" zero %d\n"
|
880
|
+
" addend %d\n"
|
881
|
+
" next %d\n"
|
882
|
+
" bind %d\n" // == 1
|
883
|
+
" auth %d\n", // == 0
|
884
|
+
buf.bind24.ordinal,
|
885
|
+
buf.bind24.zero,
|
886
|
+
buf.bind24.addend,
|
887
|
+
buf.bind24.next,
|
888
|
+
buf.bind24.bind,
|
889
|
+
buf.bind24.auth);
|
890
|
+
}
|
891
|
+
} else {
|
892
|
+
if (!buf.rebase.bind) {
|
893
|
+
DEBUG_FIXUPS(" dyld_chained_ptr_arm64e_auth_rebase\n"
|
894
|
+
" target %u\n"
|
895
|
+
" diversity %d\n"
|
896
|
+
" addrDiv %d\n"
|
897
|
+
" key %d\n"
|
898
|
+
" next %d\n"
|
899
|
+
" bind %d\n" // == 0
|
900
|
+
" auth %d\n", // == 1
|
901
|
+
buf.auth_rebase.target,
|
902
|
+
buf.auth_rebase.diversity,
|
903
|
+
buf.auth_rebase.addrDiv,
|
904
|
+
buf.auth_rebase.key,
|
905
|
+
buf.auth_rebase.next,
|
906
|
+
buf.auth_rebase.bind,
|
907
|
+
buf.auth_rebase.auth);
|
908
|
+
} else if (seg->pointer_format != DYLD_CHAINED_PTR_ARM64E_USERLAND24) {
|
909
|
+
DEBUG_FIXUPS(" dyld_chained_ptr_arm64e_auth_bind\n"
|
910
|
+
" ordinal %d\n"
|
911
|
+
" zero %d\n"
|
912
|
+
" diversity %d\n"
|
913
|
+
" addrDiv %d\n"
|
914
|
+
" key %d\n"
|
915
|
+
" next %d\n"
|
916
|
+
" bind %d\n" // == 1
|
917
|
+
" auth %d\n", // == 1
|
918
|
+
buf.auth_bind.ordinal,
|
919
|
+
buf.auth_bind.zero,
|
920
|
+
buf.auth_bind.diversity,
|
921
|
+
buf.auth_bind.addrDiv,
|
922
|
+
buf.auth_bind.key,
|
923
|
+
buf.auth_bind.next,
|
924
|
+
buf.auth_bind.bind,
|
925
|
+
buf.auth_bind.auth);
|
926
|
+
} else {
|
927
|
+
DEBUG_FIXUPS(" dyld_chained_ptr_arm64e_auth_bind24\n"
|
928
|
+
" ordinal %d\n"
|
929
|
+
" zero %d\n"
|
930
|
+
" diversity %d\n"
|
931
|
+
" addrDiv %d\n"
|
932
|
+
" key %d\n"
|
933
|
+
" next %d\n"
|
934
|
+
" bind %d\n" // == 1
|
935
|
+
" auth %d\n", // == 1
|
936
|
+
buf.auth_bind24.ordinal,
|
937
|
+
buf.auth_bind24.zero,
|
938
|
+
buf.auth_bind24.diversity,
|
939
|
+
buf.auth_bind24.addrDiv,
|
940
|
+
buf.auth_bind24.key,
|
941
|
+
buf.auth_bind24.next,
|
942
|
+
buf.auth_bind24.bind,
|
943
|
+
buf.auth_bind24.auth);
|
944
|
+
}
|
945
|
+
}
|
946
|
+
if (seg->pointer_format == DYLD_CHAINED_PTR_ARM64E_KERNEL) {
|
947
|
+
offset += buf.rebase.next * 4;
|
948
|
+
} else {
|
949
|
+
offset += buf.rebase.next * 8;
|
950
|
+
}
|
951
|
+
} while (buf.rebase.next != 0);
|
952
|
+
break;
|
953
|
+
}
|
954
|
+
default:
|
955
|
+
DEBUG_FIXUPS("unsupported pointer_format: %u\n", seg->pointer_format);
|
956
|
+
break_loop = 1;
|
957
|
+
break;
|
958
|
+
}
|
959
|
+
if (break_loop) {
|
960
|
+
break;
|
961
|
+
}
|
962
|
+
break_loop = seg->page_start[++index] & DYLD_CHAINED_PTR_START_MULTI;
|
963
|
+
} // while (1) */
|
964
|
+
}
|
965
|
+
}
|
966
|
+
#endif
|
967
|
+
rv = 0;
|
968
|
+
cleanup:
|
969
|
+
#ifdef PLTHOOK_DEBUG_FIXUPS
|
970
|
+
if (fp != NULL) {
|
971
|
+
fclose(fp);
|
972
|
+
}
|
973
|
+
#endif
|
974
|
+
if (rv != 0 && d->plthook) {
|
975
|
+
free(d->plthook);
|
976
|
+
d->plthook = NULL;
|
977
|
+
}
|
978
|
+
return rv;
|
979
|
+
}
|
980
|
+
|
981
|
+
static int set_mem_prot(plthook_t *plthook)
|
982
|
+
{
|
983
|
+
unsigned int pos = 0;
|
984
|
+
const char *name;
|
985
|
+
void **addr;
|
986
|
+
size_t start = (size_t)-1;
|
987
|
+
size_t end = 0;
|
988
|
+
mach_port_t task = mach_task_self();
|
989
|
+
vm_address_t vm_addr = 0;
|
990
|
+
vm_size_t vm_size;
|
991
|
+
vm_region_basic_info_data_64_t info;
|
992
|
+
mach_msg_type_number_t info_count = VM_REGION_BASIC_INFO_COUNT_64;
|
993
|
+
memory_object_name_t object = 0;
|
994
|
+
int idx = 0;
|
995
|
+
|
996
|
+
while (plthook_enum(plthook, &pos, &name, &addr) == 0) {
|
997
|
+
if (start > (size_t)addr) {
|
998
|
+
start = (size_t)addr;
|
999
|
+
}
|
1000
|
+
if (end < (size_t)addr) {
|
1001
|
+
end = (size_t)addr;
|
1002
|
+
}
|
1003
|
+
}
|
1004
|
+
end++;
|
1005
|
+
|
1006
|
+
while (vm_region_64(task, &vm_addr, &vm_size, VM_REGION_BASIC_INFO_64, (vm_region_info_t)&info, &info_count, &object) == KERN_SUCCESS) {
|
1007
|
+
mem_prot_t mem_prot = {vm_addr, vm_addr + vm_size, info.protection & (PROT_READ | PROT_WRITE | PROT_EXEC)};
|
1008
|
+
if (mem_prot.prot != 0 && mem_prot.start < end && start < mem_prot.end) {
|
1009
|
+
plthook->mem_prot[idx++] = mem_prot;
|
1010
|
+
if (idx == NUM_MEM_PROT) {
|
1011
|
+
break;
|
1012
|
+
}
|
1013
|
+
}
|
1014
|
+
vm_addr += vm_size;
|
1015
|
+
}
|
1016
|
+
return 0;
|
1017
|
+
}
|
1018
|
+
|
1019
|
+
static int get_mem_prot(plthook_t *plthook, void *addr)
|
1020
|
+
{
|
1021
|
+
mem_prot_t *ptr = plthook->mem_prot;
|
1022
|
+
mem_prot_t *end = ptr + NUM_MEM_PROT;
|
1023
|
+
|
1024
|
+
while (ptr < end && ptr->prot != 0) {
|
1025
|
+
if (ptr->start <= (size_t)addr && (size_t)addr < ptr->end) {
|
1026
|
+
return ptr->prot;
|
1027
|
+
}
|
1028
|
+
++ptr;
|
1029
|
+
}
|
1030
|
+
return 0;
|
1031
|
+
}
|
1032
|
+
|
423
1033
|
int plthook_enum(plthook_t *plthook, unsigned int *pos, const char **name_out, void ***addr_out)
|
1034
|
+
{
|
1035
|
+
return plthook_enum_with_prot(plthook, pos, name_out, addr_out, NULL);
|
1036
|
+
}
|
1037
|
+
|
1038
|
+
int plthook_enum_with_prot(plthook_t *plthook, unsigned int *pos, const char **name_out, void ***addr_out, int *prot)
|
424
1039
|
{
|
425
1040
|
if (*pos >= plthook->num_entries) {
|
426
1041
|
*name_out = NULL;
|
@@ -430,6 +1045,9 @@ int plthook_enum(plthook_t *plthook, unsigned int *pos, const char **name_out, v
|
|
430
1045
|
*name_out = plthook->entries[*pos].name;
|
431
1046
|
*addr_out = plthook->entries[*pos].addr;
|
432
1047
|
(*pos)++;
|
1048
|
+
if (prot != NULL) {
|
1049
|
+
*prot = get_mem_prot(plthook, *addr_out);
|
1050
|
+
}
|
433
1051
|
return 0;
|
434
1052
|
}
|
435
1053
|
|
@@ -473,7 +1091,23 @@ matched:
|
|
473
1091
|
if (oldfunc) {
|
474
1092
|
*oldfunc = *addr;
|
475
1093
|
}
|
476
|
-
|
1094
|
+
int prot = get_mem_prot(plthook, addr);
|
1095
|
+
if (prot == 0) {
|
1096
|
+
set_errmsg("Could not get the process memory permission at %p", addr);
|
1097
|
+
return PLTHOOK_INTERNAL_ERROR;
|
1098
|
+
}
|
1099
|
+
if (!(prot & PROT_WRITE)) {
|
1100
|
+
size_t page_size = sysconf(_SC_PAGESIZE);
|
1101
|
+
void *base = (void*)((size_t)addr & ~(page_size - 1));
|
1102
|
+
if (mprotect(base, page_size, PROT_READ | PROT_WRITE) != 0) {
|
1103
|
+
set_errmsg("Cannot change memory protection at address %p", base);
|
1104
|
+
return PLTHOOK_INTERNAL_ERROR;
|
1105
|
+
}
|
1106
|
+
*addr = funcaddr;
|
1107
|
+
mprotect(base, page_size, prot);
|
1108
|
+
} else {
|
1109
|
+
*addr = funcaddr;
|
1110
|
+
}
|
477
1111
|
return 0;
|
478
1112
|
}
|
479
1113
|
if (rv == EOF) {
|