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_elf.c
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
/* -*- indent-tabs-mode: nil -*-
|
2
2
|
*
|
3
|
-
* plthook_elf.c --
|
3
|
+
* plthook_elf.c -- implementation of plthook for ELF format
|
4
4
|
*
|
5
5
|
* URL: https://github.com/kubo/plthook
|
6
6
|
*
|
7
7
|
* ------------------------------------------------------
|
8
8
|
*
|
9
|
-
* Copyright 2013-
|
9
|
+
* Copyright 2013-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:
|
@@ -50,6 +50,7 @@
|
|
50
50
|
#include <dlfcn.h>
|
51
51
|
#ifdef __sun
|
52
52
|
#include <sys/auxv.h>
|
53
|
+
#include <procfs.h>
|
53
54
|
#define ELF_TARGET_ALL
|
54
55
|
#endif /* __sun */
|
55
56
|
#ifdef __FreeBSD__
|
@@ -61,6 +62,10 @@
|
|
61
62
|
#include <link.h>
|
62
63
|
#include "plthook.h"
|
63
64
|
|
65
|
+
#if defined __UCLIBC__ && !defined RTLD_NOLOAD
|
66
|
+
#define RTLD_NOLOAD 0
|
67
|
+
#endif
|
68
|
+
|
64
69
|
#ifndef __GNUC__
|
65
70
|
#define __attribute__(arg)
|
66
71
|
#endif
|
@@ -75,46 +80,66 @@
|
|
75
80
|
|
76
81
|
#if defined __x86_64__ || defined __x86_64
|
77
82
|
#define R_JUMP_SLOT R_X86_64_JUMP_SLOT
|
78
|
-
#define Elf_Plt_Rel Elf_Rela
|
79
|
-
#define PLT_DT_REL DT_RELA
|
80
83
|
#define R_GLOBAL_DATA R_X86_64_GLOB_DAT
|
81
84
|
#elif defined __i386__ || defined __i386
|
82
85
|
#define R_JUMP_SLOT R_386_JMP_SLOT
|
83
|
-
#define Elf_Plt_Rel Elf_Rel
|
84
|
-
#define PLT_DT_REL DT_REL
|
85
86
|
#define R_GLOBAL_DATA R_386_GLOB_DAT
|
87
|
+
#define USE_REL
|
86
88
|
#elif defined __arm__ || defined __arm
|
87
89
|
#define R_JUMP_SLOT R_ARM_JUMP_SLOT
|
88
|
-
#define
|
90
|
+
#define R_GLOBAL_DATA R_ARM_GLOB_DAT
|
91
|
+
#define USE_REL
|
89
92
|
#elif defined __aarch64__ || defined __aarch64 /* ARM64 */
|
90
93
|
#define R_JUMP_SLOT R_AARCH64_JUMP_SLOT
|
91
|
-
#define
|
94
|
+
#define R_GLOBAL_DATA R_AARCH64_GLOB_DAT
|
92
95
|
#elif defined __powerpc64__
|
93
96
|
#define R_JUMP_SLOT R_PPC64_JMP_SLOT
|
94
|
-
#define
|
97
|
+
#define R_GLOBAL_DATA R_PPC64_GLOB_DAT
|
95
98
|
#elif defined __powerpc__
|
96
99
|
#define R_JUMP_SLOT R_PPC_JMP_SLOT
|
97
|
-
#define
|
100
|
+
#define R_GLOBAL_DATA R_PPC_GLOB_DAT
|
101
|
+
#elif defined __riscv
|
102
|
+
#define R_JUMP_SLOT R_RISCV_JUMP_SLOT
|
103
|
+
#if __riscv_xlen == 32
|
104
|
+
#define R_GLOBAL_DATA R_RISCV_32
|
105
|
+
#elif __riscv_xlen == 64
|
106
|
+
#define R_GLOBAL_DATA R_RISCV_64
|
107
|
+
#else
|
108
|
+
#error unsupported RISCV implementation
|
109
|
+
#endif
|
98
110
|
#elif 0 /* disabled because not tested */ && (defined __sparcv9 || defined __sparc_v9__)
|
99
111
|
#define R_JUMP_SLOT R_SPARC_JMP_SLOT
|
100
|
-
#define Elf_Plt_Rel Elf_Rela
|
101
112
|
#elif 0 /* disabled because not tested */ && (defined __sparc || defined __sparc__)
|
102
113
|
#define R_JUMP_SLOT R_SPARC_JMP_SLOT
|
103
|
-
#define Elf_Plt_Rel Elf_Rela
|
104
114
|
#elif 0 /* disabled because not tested */ && (defined __ia64 || defined __ia64__)
|
105
115
|
#define R_JUMP_SLOT R_IA64_IPLTMSB
|
106
|
-
#define Elf_Plt_Rel Elf_Rela
|
107
116
|
#else
|
108
117
|
#error unsupported OS
|
109
118
|
#endif
|
110
119
|
|
120
|
+
#ifdef USE_REL
|
121
|
+
#define Elf_Plt_Rel Elf_Rel
|
122
|
+
#define PLT_DT_REL DT_REL
|
123
|
+
#define PLT_DT_RELSZ DT_RELSZ
|
124
|
+
#define PLT_DT_RELENT DT_RELENT
|
125
|
+
#else
|
126
|
+
#define Elf_Plt_Rel Elf_Rela
|
127
|
+
#define PLT_DT_REL DT_RELA
|
128
|
+
#define PLT_DT_RELSZ DT_RELASZ
|
129
|
+
#define PLT_DT_RELENT DT_RELAENT
|
130
|
+
#endif
|
131
|
+
|
111
132
|
#if defined __LP64__
|
112
133
|
#ifndef ELF_CLASS
|
113
134
|
#define ELF_CLASS ELFCLASS64
|
114
135
|
#endif
|
115
136
|
#define SIZE_T_FMT "lu"
|
116
137
|
#define ELF_WORD_FMT "u"
|
138
|
+
#ifdef __ANDROID__
|
139
|
+
#define ELF_XWORD_FMT "llu"
|
140
|
+
#else
|
117
141
|
#define ELF_XWORD_FMT "lu"
|
142
|
+
#endif
|
118
143
|
#define ELF_SXWORD_FMT "ld"
|
119
144
|
#define Elf_Half Elf64_Half
|
120
145
|
#define Elf_Xword Elf64_Xword
|
@@ -162,43 +187,82 @@
|
|
162
187
|
#endif
|
163
188
|
#endif /* __LP64__ */
|
164
189
|
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
190
|
+
typedef struct mem_prot {
|
191
|
+
size_t start;
|
192
|
+
size_t end;
|
193
|
+
int prot;
|
194
|
+
} mem_prot_t;
|
195
|
+
|
196
|
+
#define NUM_MEM_PROT 20
|
171
197
|
|
172
198
|
struct plthook {
|
173
199
|
const Elf_Sym *dynsym;
|
174
200
|
const char *dynstr;
|
175
201
|
size_t dynstr_size;
|
176
202
|
const char *plt_addr_base;
|
177
|
-
const Elf_Plt_Rel *
|
178
|
-
size_t
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
const char *relro_end;
|
203
|
+
const Elf_Plt_Rel *rela_plt;
|
204
|
+
size_t rela_plt_cnt;
|
205
|
+
#ifdef R_GLOBAL_DATA
|
206
|
+
const Elf_Plt_Rel *rela_dyn;
|
207
|
+
size_t rela_dyn_cnt;
|
183
208
|
#endif
|
209
|
+
mem_prot_t mem_prot[NUM_MEM_PROT];
|
184
210
|
};
|
185
211
|
|
186
212
|
static char errmsg[512];
|
187
|
-
|
188
|
-
#ifdef SUPPORT_RELRO
|
189
213
|
static size_t page_size;
|
190
|
-
#
|
214
|
+
#define ALIGN_ADDR(addr) ((void*)((size_t)(addr) & ~(page_size - 1)))
|
191
215
|
|
192
216
|
static int plthook_open_executable(plthook_t **plthook_out);
|
193
217
|
static int plthook_open_shared_library(plthook_t **plthook_out, const char *filename);
|
194
218
|
static const Elf_Dyn *find_dyn_by_tag(const Elf_Dyn *dyn, Elf_Sxword tag);
|
195
|
-
|
196
|
-
|
197
|
-
|
219
|
+
|
220
|
+
typedef struct mem_prot_iter mem_prot_iter_t;
|
221
|
+
static int mem_prot_begin(mem_prot_iter_t *iter);
|
222
|
+
static int mem_prot_next(mem_prot_iter_t *iter, mem_prot_t *mem_prot);
|
223
|
+
static void mem_prot_end(mem_prot_iter_t *iter);
|
224
|
+
|
198
225
|
static int plthook_open_real(plthook_t **plthook_out, struct link_map *lmap);
|
226
|
+
static int plthook_set_mem_prot(plthook_t *plthook);
|
227
|
+
static int plthook_get_mem_prot(plthook_t *plthook, void *addr);
|
228
|
+
#if defined __FreeBSD__ || defined __sun
|
199
229
|
static int check_elf_header(const Elf_Ehdr *ehdr);
|
230
|
+
#endif
|
200
231
|
static void set_errmsg(const char *fmt, ...) __attribute__((__format__ (__printf__, 1, 2)));
|
201
232
|
|
233
|
+
#if defined __ANDROID__ || defined __UCLIBC__
|
234
|
+
struct dl_iterate_data {
|
235
|
+
char* addr;
|
236
|
+
struct link_map lmap;
|
237
|
+
};
|
238
|
+
|
239
|
+
static int dl_iterate_cb(struct dl_phdr_info *info, size_t size, void *cb_data)
|
240
|
+
{
|
241
|
+
struct dl_iterate_data *data = (struct dl_iterate_data*)cb_data;
|
242
|
+
Elf_Half idx = 0;
|
243
|
+
|
244
|
+
for (idx = 0; idx < info->dlpi_phnum; ++idx) {
|
245
|
+
const Elf_Phdr *phdr = &info->dlpi_phdr[idx];
|
246
|
+
char* base = (char*)info->dlpi_addr + phdr->p_vaddr;
|
247
|
+
if (base <= data->addr && data->addr < base + phdr->p_memsz) {
|
248
|
+
break;
|
249
|
+
}
|
250
|
+
}
|
251
|
+
if (idx == info->dlpi_phnum) {
|
252
|
+
return 0;
|
253
|
+
}
|
254
|
+
for (idx = 0; idx < info->dlpi_phnum; ++idx) {
|
255
|
+
const Elf_Phdr *phdr = &info->dlpi_phdr[idx];
|
256
|
+
if (phdr->p_type == PT_DYNAMIC) {
|
257
|
+
data->lmap.l_addr = info->dlpi_addr;
|
258
|
+
data->lmap.l_ld = (Elf_Dyn*)(info->dlpi_addr + phdr->p_vaddr);
|
259
|
+
return 1;
|
260
|
+
}
|
261
|
+
}
|
262
|
+
return 0;
|
263
|
+
}
|
264
|
+
#endif
|
265
|
+
|
202
266
|
int plthook_open(plthook_t **plthook_out, const char *filename)
|
203
267
|
{
|
204
268
|
*plthook_out = NULL;
|
@@ -211,6 +275,27 @@ int plthook_open(plthook_t **plthook_out, const char *filename)
|
|
211
275
|
|
212
276
|
int plthook_open_by_handle(plthook_t **plthook_out, void *hndl)
|
213
277
|
{
|
278
|
+
#if defined __ANDROID__ || defined __UCLIBC__
|
279
|
+
const static char *symbols[] = {
|
280
|
+
"__INIT_ARRAY__",
|
281
|
+
"_end",
|
282
|
+
"_start"
|
283
|
+
};
|
284
|
+
size_t i;
|
285
|
+
|
286
|
+
if (hndl == NULL) {
|
287
|
+
set_errmsg("NULL handle");
|
288
|
+
return PLTHOOK_FILE_NOT_FOUND;
|
289
|
+
}
|
290
|
+
for (i = 0; i < sizeof(symbols)/sizeof(symbols[0]); i++) {
|
291
|
+
char *addr = dlsym(hndl, symbols[i]);
|
292
|
+
if (addr != NULL) {
|
293
|
+
return plthook_open_by_address(plthook_out, addr - 1);
|
294
|
+
}
|
295
|
+
}
|
296
|
+
set_errmsg("Could not find an address in the specified handle.");
|
297
|
+
return PLTHOOK_INTERNAL_ERROR;
|
298
|
+
#else
|
214
299
|
struct link_map *lmap = NULL;
|
215
300
|
|
216
301
|
if (hndl == NULL) {
|
@@ -222,12 +307,22 @@ int plthook_open_by_handle(plthook_t **plthook_out, void *hndl)
|
|
222
307
|
return PLTHOOK_FILE_NOT_FOUND;
|
223
308
|
}
|
224
309
|
return plthook_open_real(plthook_out, lmap);
|
310
|
+
#endif
|
225
311
|
}
|
226
312
|
|
227
313
|
int plthook_open_by_address(plthook_t **plthook_out, void *address)
|
228
314
|
{
|
229
315
|
#if defined __FreeBSD__
|
230
316
|
return PLTHOOK_NOT_IMPLEMENTED;
|
317
|
+
#elif defined __ANDROID__ || defined __UCLIBC__
|
318
|
+
struct dl_iterate_data data = {0,};
|
319
|
+
data.addr = address;
|
320
|
+
dl_iterate_phdr(dl_iterate_cb, &data);
|
321
|
+
if (data.lmap.l_ld == NULL) {
|
322
|
+
set_errmsg("Could not find memory region containing address %p", address);
|
323
|
+
return PLTHOOK_INTERNAL_ERROR;
|
324
|
+
}
|
325
|
+
return plthook_open_real(plthook_out, &data.lmap);
|
231
326
|
#else
|
232
327
|
Dl_info info;
|
233
328
|
struct link_map *lmap = NULL;
|
@@ -243,7 +338,9 @@ int plthook_open_by_address(plthook_t **plthook_out, void *address)
|
|
243
338
|
|
244
339
|
static int plthook_open_executable(plthook_t **plthook_out)
|
245
340
|
{
|
246
|
-
#if defined
|
341
|
+
#if defined __ANDROID__ || defined __UCLIBC__
|
342
|
+
return plthook_open_shared_library(plthook_out, NULL);
|
343
|
+
#elif defined __linux__
|
247
344
|
return plthook_open_real(plthook_out, _r_debug.r_map);
|
248
345
|
#elif defined __sun
|
249
346
|
const char *auxv_file = "/proc/self/auxv";
|
@@ -280,12 +377,21 @@ static int plthook_open_executable(plthook_t **plthook_out)
|
|
280
377
|
static int plthook_open_shared_library(plthook_t **plthook_out, const char *filename)
|
281
378
|
{
|
282
379
|
void *hndl = dlopen(filename, RTLD_LAZY | RTLD_NOLOAD);
|
380
|
+
#if defined __ANDROID__ || defined __UCLIBC__
|
381
|
+
int rv;
|
382
|
+
#else
|
283
383
|
struct link_map *lmap = NULL;
|
384
|
+
#endif
|
284
385
|
|
285
386
|
if (hndl == NULL) {
|
286
387
|
set_errmsg("dlopen error: %s", dlerror());
|
287
388
|
return PLTHOOK_FILE_NOT_FOUND;
|
288
389
|
}
|
390
|
+
#if defined __ANDROID__ || defined __UCLIBC__
|
391
|
+
rv = plthook_open_by_handle(plthook_out, hndl);
|
392
|
+
dlclose(hndl);
|
393
|
+
return rv;
|
394
|
+
#else
|
289
395
|
if (dlinfo(hndl, RTLD_DI_LINKMAP, &lmap) != 0) {
|
290
396
|
set_errmsg("dlinfo error");
|
291
397
|
dlclose(hndl);
|
@@ -293,6 +399,7 @@ static int plthook_open_shared_library(plthook_t **plthook_out, const char *file
|
|
293
399
|
}
|
294
400
|
dlclose(hndl);
|
295
401
|
return plthook_open_real(plthook_out, lmap);
|
402
|
+
#endif
|
296
403
|
}
|
297
404
|
|
298
405
|
static const Elf_Dyn *find_dyn_by_tag(const Elf_Dyn *dyn, Elf_Sxword tag)
|
@@ -306,135 +413,170 @@ static const Elf_Dyn *find_dyn_by_tag(const Elf_Dyn *dyn, Elf_Sxword tag)
|
|
306
413
|
return NULL;
|
307
414
|
}
|
308
415
|
|
309
|
-
#ifdef
|
310
|
-
|
311
|
-
static const char *get_mapped_file(const void *address, char *buf, int *err)
|
312
|
-
{
|
313
|
-
unsigned long addr = (unsigned long)address;
|
416
|
+
#ifdef __linux__
|
417
|
+
struct mem_prot_iter {
|
314
418
|
FILE *fp;
|
419
|
+
};
|
315
420
|
|
316
|
-
|
317
|
-
|
421
|
+
static int mem_prot_begin(mem_prot_iter_t *iter)
|
422
|
+
{
|
423
|
+
iter->fp = fopen("/proc/self/maps", "r");
|
424
|
+
if (iter->fp == NULL) {
|
318
425
|
set_errmsg("failed to open /proc/self/maps");
|
319
|
-
|
320
|
-
return NULL;
|
426
|
+
return -1;
|
321
427
|
}
|
322
|
-
|
428
|
+
return 0;
|
429
|
+
}
|
430
|
+
|
431
|
+
static int mem_prot_next(mem_prot_iter_t *iter, mem_prot_t *mem_prot)
|
432
|
+
{
|
433
|
+
char buf[PATH_MAX];
|
434
|
+
char perms[5];
|
435
|
+
int bol = 1; /* beginnng of line */
|
436
|
+
|
437
|
+
while (fgets(buf, PATH_MAX, iter->fp) != NULL) {
|
323
438
|
unsigned long start, end;
|
324
|
-
int
|
439
|
+
int eol = (strchr(buf, '\n') != NULL); /* end of line */
|
440
|
+
if (bol) {
|
441
|
+
/* The fgets reads from the beginning of a line. */
|
442
|
+
if (!eol) {
|
443
|
+
/* The next fgets reads from the middle of the same line. */
|
444
|
+
bol = 0;
|
445
|
+
}
|
446
|
+
} else {
|
447
|
+
/* The fgets reads from the middle of a line. */
|
448
|
+
if (eol) {
|
449
|
+
/* The next fgets reads from the beginning of a line. */
|
450
|
+
bol = 1;
|
451
|
+
}
|
452
|
+
continue;
|
453
|
+
}
|
325
454
|
|
326
|
-
sscanf(buf, "%lx-%lx
|
327
|
-
if (offset == 0) {
|
455
|
+
if (sscanf(buf, "%lx-%lx %4s", &start, &end, perms) != 3) {
|
328
456
|
continue;
|
329
457
|
}
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
458
|
+
mem_prot->start = start;
|
459
|
+
mem_prot->end = end;
|
460
|
+
mem_prot->prot = 0;
|
461
|
+
if (perms[0] == 'r') {
|
462
|
+
mem_prot->prot |= PROT_READ;
|
463
|
+
}
|
464
|
+
if (perms[1] == 'w') {
|
465
|
+
mem_prot->prot |= PROT_WRITE;
|
466
|
+
}
|
467
|
+
if (perms[2] == 'x') {
|
468
|
+
mem_prot->prot |= PROT_EXEC;
|
341
469
|
}
|
470
|
+
return 0;
|
471
|
+
}
|
472
|
+
return -1;
|
473
|
+
}
|
474
|
+
|
475
|
+
static void mem_prot_end(mem_prot_iter_t *iter)
|
476
|
+
{
|
477
|
+
if (iter->fp != NULL) {
|
478
|
+
fclose(iter->fp);
|
342
479
|
}
|
343
|
-
fclose(fp);
|
344
|
-
set_errmsg("Could not find a mapped file reagion containing %p", address);
|
345
|
-
*err = PLTHOOK_INTERNAL_ERROR;
|
346
|
-
return NULL;
|
347
480
|
}
|
348
481
|
#elif defined __FreeBSD__
|
349
|
-
|
482
|
+
struct mem_prot_iter {
|
483
|
+
struct kinfo_vmentry *kve;
|
484
|
+
int idx;
|
485
|
+
int num;
|
486
|
+
};
|
487
|
+
|
488
|
+
static int mem_prot_begin(mem_prot_iter_t *iter)
|
350
489
|
{
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
top = kinfo_getvmmap(getpid(), &cnt);
|
356
|
-
if (top == NULL) {
|
357
|
-
fprintf(stderr, "failed to call kinfo_getvmmap()\n");
|
358
|
-
*err = PLTHOOK_INTERNAL_ERROR;
|
359
|
-
return NULL;
|
360
|
-
}
|
361
|
-
for (i = 0; i < cnt; i++) {
|
362
|
-
struct kinfo_vmentry *kve = top + i;
|
363
|
-
|
364
|
-
if (kve->kve_start < addr && addr < kve->kve_end) {
|
365
|
-
strncpy(buf, kve->kve_path, PATH_MAX);
|
366
|
-
free(top);
|
367
|
-
return buf;
|
368
|
-
}
|
490
|
+
iter->kve = kinfo_getvmmap(getpid(), &iter->num);
|
491
|
+
if (iter->kve == NULL) {
|
492
|
+
set_errmsg("failed to call kinfo_getvmmap()\n");
|
493
|
+
return -1;
|
369
494
|
}
|
370
|
-
|
371
|
-
|
372
|
-
*err = PLTHOOK_INTERNAL_ERROR;
|
373
|
-
return NULL;
|
495
|
+
iter->idx = 0;
|
496
|
+
return 0;
|
374
497
|
}
|
375
|
-
|
376
|
-
static
|
498
|
+
|
499
|
+
static int mem_prot_next(mem_prot_iter_t *iter, mem_prot_t *mem_prot)
|
377
500
|
{
|
378
|
-
|
379
|
-
|
380
|
-
|
501
|
+
if (iter->idx >= iter->num) {
|
502
|
+
return -1;
|
503
|
+
}
|
504
|
+
struct kinfo_vmentry *kve = &iter->kve[iter->idx++];
|
505
|
+
mem_prot->start = kve->kve_start;
|
506
|
+
mem_prot->end = kve->kve_end;
|
507
|
+
mem_prot->prot = 0;
|
508
|
+
if (kve->kve_protection & KVME_PROT_READ) {
|
509
|
+
mem_prot->prot |= PROT_READ;
|
510
|
+
}
|
511
|
+
if (kve->kve_protection & KVME_PROT_WRITE) {
|
512
|
+
mem_prot->prot |= PROT_WRITE;
|
513
|
+
}
|
514
|
+
if (kve->kve_protection & KVME_PROT_EXEC) {
|
515
|
+
mem_prot->prot |= PROT_EXEC;
|
516
|
+
}
|
517
|
+
return 0;
|
381
518
|
}
|
382
|
-
#endif
|
383
519
|
|
384
|
-
static
|
520
|
+
static void mem_prot_end(mem_prot_iter_t *iter)
|
385
521
|
{
|
386
|
-
|
387
|
-
|
522
|
+
if (iter->kve != NULL) {
|
523
|
+
free(iter->kve);
|
524
|
+
}
|
525
|
+
}
|
526
|
+
#elif defined(__sun)
|
527
|
+
struct mem_prot_iter {
|
388
528
|
FILE *fp;
|
389
|
-
|
390
|
-
|
391
|
-
|
529
|
+
prmap_t maps[20];
|
530
|
+
size_t idx;
|
531
|
+
size_t num;
|
532
|
+
};
|
392
533
|
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
534
|
+
static int mem_prot_begin(mem_prot_iter_t *iter)
|
535
|
+
{
|
536
|
+
iter->fp = fopen("/proc/self/map", "r");
|
537
|
+
if (iter->fp == NULL) {
|
538
|
+
set_errmsg("failed to open /proc/self/map");
|
539
|
+
return -1;
|
540
|
+
}
|
541
|
+
iter->idx = iter->num = 0;
|
542
|
+
return 0;
|
543
|
+
}
|
544
|
+
|
545
|
+
static int mem_prot_next(mem_prot_iter_t *iter, mem_prot_t *mem_prot)
|
546
|
+
{
|
547
|
+
prmap_t *map;
|
397
548
|
|
398
|
-
|
399
|
-
|
400
|
-
|
549
|
+
if (iter->idx == iter->num) {
|
550
|
+
iter->num = fread(iter->maps, sizeof(iter->maps[0]), sizeof(iter->maps) / sizeof(iter->maps[0]), iter->fp);
|
551
|
+
if (iter->num == 0) {
|
552
|
+
return -1;
|
401
553
|
}
|
554
|
+
iter->idx = 0;
|
402
555
|
}
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
556
|
+
map = &iter->maps[iter->idx++];
|
557
|
+
mem_prot->start = map->pr_vaddr;
|
558
|
+
mem_prot->end = map->pr_vaddr + map->pr_size;
|
559
|
+
mem_prot->prot = 0;
|
560
|
+
if (map->pr_mflags & MA_READ) {
|
561
|
+
mem_prot->prot |= PROT_READ;
|
407
562
|
}
|
408
|
-
if (
|
409
|
-
|
410
|
-
fclose(fp);
|
411
|
-
return PLTHOOK_INVALID_FILE_FORMAT;
|
563
|
+
if (map->pr_mflags & MA_WRITE) {
|
564
|
+
mem_prot->prot |= PROT_WRITE;
|
412
565
|
}
|
413
|
-
|
414
|
-
|
415
|
-
fclose(fp);
|
416
|
-
return rv;
|
566
|
+
if (map->pr_mflags & MA_EXEC) {
|
567
|
+
mem_prot->prot |= PROT_EXEC;
|
417
568
|
}
|
569
|
+
return 0;
|
570
|
+
}
|
418
571
|
|
419
|
-
|
420
|
-
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
if (fread(&phdr, sizeof(phdr), 1, fp) != 1) {
|
425
|
-
set_errmsg("failed to read the program header table.");
|
426
|
-
fclose(fp);
|
427
|
-
return PLTHOOK_INVALID_FILE_FORMAT;
|
428
|
-
}
|
429
|
-
if (phdr.p_type == PT_GNU_RELRO) {
|
430
|
-
plthook->relro_start = plthook->plt_addr_base + phdr.p_vaddr;
|
431
|
-
plthook->relro_end = plthook->relro_start + phdr.p_memsz;
|
432
|
-
break;
|
433
|
-
}
|
572
|
+
static void mem_prot_end(mem_prot_iter_t *iter)
|
573
|
+
{
|
574
|
+
if (iter->fp != NULL) {
|
575
|
+
fclose(iter->fp);
|
434
576
|
}
|
435
|
-
fclose(fp);
|
436
|
-
return 0;
|
437
577
|
}
|
578
|
+
#else
|
579
|
+
#error Unsupported platform
|
438
580
|
#endif
|
439
581
|
|
440
582
|
static int plthook_open_real(plthook_t **plthook_out, struct link_map *lmap)
|
@@ -443,13 +585,30 @@ static int plthook_open_real(plthook_t **plthook_out, struct link_map *lmap)
|
|
443
585
|
const Elf_Dyn *dyn;
|
444
586
|
const char *dyn_addr_base = NULL;
|
445
587
|
|
588
|
+
if (page_size == 0) {
|
589
|
+
page_size = sysconf(_SC_PAGESIZE);
|
590
|
+
}
|
591
|
+
|
446
592
|
#if defined __linux__
|
447
593
|
plthook.plt_addr_base = (char*)lmap->l_addr;
|
594
|
+
#if defined __riscv
|
595
|
+
const Elf_Ehdr *ehdr = (const Elf_Ehdr*)lmap->l_addr;
|
596
|
+
if (ehdr->e_type == ET_DYN) {
|
597
|
+
dyn_addr_base = (const char*)lmap->l_addr;
|
598
|
+
}
|
599
|
+
#endif
|
600
|
+
#if defined __ANDROID__ || defined __UCLIBC__
|
601
|
+
dyn_addr_base = (const char*)lmap->l_addr;
|
602
|
+
#endif
|
448
603
|
#elif defined __FreeBSD__ || defined __sun
|
604
|
+
#if __FreeBSD__ >= 13
|
605
|
+
const Elf_Ehdr *ehdr = (const Elf_Ehdr*)lmap->l_base;
|
606
|
+
#else
|
449
607
|
const Elf_Ehdr *ehdr = (const Elf_Ehdr*)lmap->l_addr;
|
450
|
-
|
451
|
-
|
452
|
-
|
608
|
+
#endif
|
609
|
+
int rv_ = check_elf_header(ehdr);
|
610
|
+
if (rv_ != 0) {
|
611
|
+
return rv_;
|
453
612
|
}
|
454
613
|
if (ehdr->e_type == ET_DYN) {
|
455
614
|
dyn_addr_base = (const char*)lmap->l_addr;
|
@@ -496,64 +655,53 @@ static int plthook_open_real(plthook_t **plthook_out, struct link_map *lmap)
|
|
496
655
|
|
497
656
|
/* get .rela.plt or .rel.plt section */
|
498
657
|
dyn = find_dyn_by_tag(lmap->l_ld, DT_JMPREL);
|
499
|
-
|
500
|
-
|
501
|
-
if (dyn == NULL) {
|
502
|
-
/* get .rela.dyn or .rel.dyn section */
|
503
|
-
dyn = find_dyn_by_tag(lmap->l_ld, PLT_DT_REL);
|
504
|
-
plthook.r_type = R_GLOBAL_DATA;
|
505
|
-
}
|
506
|
-
#endif
|
507
|
-
if (dyn == NULL) {
|
508
|
-
set_errmsg("failed to find DT_JMPREL");
|
509
|
-
return PLTHOOK_INTERNAL_ERROR;
|
510
|
-
}
|
511
|
-
plthook.plt = (const Elf_Plt_Rel *)(dyn_addr_base + dyn->d_un.d_ptr);
|
512
|
-
|
513
|
-
if (plthook.r_type == R_JUMP_SLOT) {
|
514
|
-
/* get total size of .rela.plt or .rel.plt */
|
658
|
+
if (dyn != NULL) {
|
659
|
+
plthook.rela_plt = (const Elf_Plt_Rel *)(dyn_addr_base + dyn->d_un.d_ptr);
|
515
660
|
dyn = find_dyn_by_tag(lmap->l_ld, DT_PLTRELSZ);
|
516
661
|
if (dyn == NULL) {
|
517
662
|
set_errmsg("failed to find DT_PLTRELSZ");
|
518
663
|
return PLTHOOK_INTERNAL_ERROR;
|
519
664
|
}
|
520
|
-
|
521
|
-
|
522
|
-
#ifdef
|
523
|
-
|
524
|
-
|
525
|
-
|
665
|
+
plthook.rela_plt_cnt = dyn->d_un.d_val / sizeof(Elf_Plt_Rel);
|
666
|
+
}
|
667
|
+
#ifdef R_GLOBAL_DATA
|
668
|
+
/* get .rela.dyn or .rel.dyn section */
|
669
|
+
dyn = find_dyn_by_tag(lmap->l_ld, PLT_DT_REL);
|
670
|
+
if (dyn != NULL) {
|
526
671
|
size_t total_size, elem_size;
|
527
672
|
|
528
|
-
|
673
|
+
plthook.rela_dyn = (const Elf_Plt_Rel *)(dyn_addr_base + dyn->d_un.d_ptr);
|
674
|
+
dyn = find_dyn_by_tag(lmap->l_ld, PLT_DT_RELSZ);
|
529
675
|
if (dyn == NULL) {
|
530
|
-
set_errmsg("failed to find
|
676
|
+
set_errmsg("failed to find PLT_DT_RELSZ");
|
531
677
|
return PLTHOOK_INTERNAL_ERROR;
|
532
678
|
}
|
533
679
|
total_size = dyn->d_un.d_ptr;
|
534
680
|
|
535
|
-
dyn = find_dyn_by_tag(lmap->l_ld,
|
681
|
+
dyn = find_dyn_by_tag(lmap->l_ld, PLT_DT_RELENT);
|
536
682
|
if (dyn == NULL) {
|
537
|
-
set_errmsg("failed to find
|
683
|
+
set_errmsg("failed to find PLT_DT_RELENT");
|
538
684
|
return PLTHOOK_INTERNAL_ERROR;
|
539
685
|
}
|
540
686
|
elem_size = dyn->d_un.d_ptr;
|
541
|
-
plthook.
|
542
|
-
#endif
|
687
|
+
plthook.rela_dyn_cnt = total_size / elem_size;
|
543
688
|
}
|
689
|
+
#endif
|
544
690
|
|
545
|
-
#ifdef
|
546
|
-
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
}
|
691
|
+
#ifdef R_GLOBAL_DATA
|
692
|
+
if (plthook.rela_plt == NULL && plthook.rela_dyn == NULL) {
|
693
|
+
set_errmsg("failed to find either of DT_JMPREL and DT_REL");
|
694
|
+
return PLTHOOK_INTERNAL_ERROR;
|
695
|
+
}
|
696
|
+
#else
|
697
|
+
if (plthook.rela_plt == NULL) {
|
698
|
+
set_errmsg("failed to find DT_JMPREL");
|
699
|
+
return PLTHOOK_INTERNAL_ERROR;
|
555
700
|
}
|
556
701
|
#endif
|
702
|
+
if (plthook_set_mem_prot(&plthook)) {
|
703
|
+
return PLTHOOK_INTERNAL_ERROR;
|
704
|
+
}
|
557
705
|
|
558
706
|
*plthook_out = malloc(sizeof(plthook_t));
|
559
707
|
if (*plthook_out == NULL) {
|
@@ -564,6 +712,54 @@ static int plthook_open_real(plthook_t **plthook_out, struct link_map *lmap)
|
|
564
712
|
return 0;
|
565
713
|
}
|
566
714
|
|
715
|
+
static int plthook_set_mem_prot(plthook_t *plthook)
|
716
|
+
{
|
717
|
+
unsigned int pos = 0;
|
718
|
+
const char *name;
|
719
|
+
void **addr;
|
720
|
+
size_t start = (size_t)-1;
|
721
|
+
size_t end = 0;
|
722
|
+
mem_prot_iter_t iter;
|
723
|
+
mem_prot_t mem_prot;
|
724
|
+
int idx = 0;
|
725
|
+
|
726
|
+
while (plthook_enum(plthook, &pos, &name, &addr) == 0) {
|
727
|
+
if (start > (size_t)addr) {
|
728
|
+
start = (size_t)addr;
|
729
|
+
}
|
730
|
+
if (end < (size_t)addr) {
|
731
|
+
end = (size_t)addr;
|
732
|
+
}
|
733
|
+
}
|
734
|
+
end++;
|
735
|
+
|
736
|
+
if (mem_prot_begin(&iter) != 0) {
|
737
|
+
return PLTHOOK_INTERNAL_ERROR;
|
738
|
+
}
|
739
|
+
while (mem_prot_next(&iter, &mem_prot) == 0 && idx < NUM_MEM_PROT) {
|
740
|
+
if (mem_prot.prot != 0 && mem_prot.start < end && start < mem_prot.end) {
|
741
|
+
plthook->mem_prot[idx++] = mem_prot;
|
742
|
+
}
|
743
|
+
}
|
744
|
+
mem_prot_end(&iter);
|
745
|
+
return 0;
|
746
|
+
}
|
747
|
+
|
748
|
+
static int plthook_get_mem_prot(plthook_t *plthook, void *addr)
|
749
|
+
{
|
750
|
+
mem_prot_t *ptr = plthook->mem_prot;
|
751
|
+
mem_prot_t *end = ptr + NUM_MEM_PROT;
|
752
|
+
|
753
|
+
while (ptr < end && ptr->prot != 0) {
|
754
|
+
if (ptr->start <= (size_t)addr && (size_t)addr < ptr->end) {
|
755
|
+
return ptr->prot;
|
756
|
+
}
|
757
|
+
++ptr;
|
758
|
+
}
|
759
|
+
return 0;
|
760
|
+
}
|
761
|
+
|
762
|
+
#if defined __FreeBSD__ || defined __sun
|
567
763
|
static int check_elf_header(const Elf_Ehdr *ehdr)
|
568
764
|
{
|
569
765
|
static const unsigned short s = 1;
|
@@ -610,26 +806,55 @@ static int check_elf_header(const Elf_Ehdr *ehdr)
|
|
610
806
|
}
|
611
807
|
return 0;
|
612
808
|
}
|
809
|
+
#endif
|
810
|
+
|
811
|
+
static int check_rel(const plthook_t *plthook, const Elf_Plt_Rel *plt, Elf_Xword r_type, const char **name_out, void ***addr_out)
|
812
|
+
{
|
813
|
+
if (ELF_R_TYPE(plt->r_info) == r_type) {
|
814
|
+
size_t idx = ELF_R_SYM(plt->r_info);
|
815
|
+
idx = plthook->dynsym[idx].st_name;
|
816
|
+
if (idx + 1 > plthook->dynstr_size) {
|
817
|
+
set_errmsg("too big section header string table index: %" SIZE_T_FMT, idx);
|
818
|
+
return PLTHOOK_INVALID_FILE_FORMAT;
|
819
|
+
}
|
820
|
+
*name_out = plthook->dynstr + idx;
|
821
|
+
*addr_out = (void**)(plthook->plt_addr_base + plt->r_offset);
|
822
|
+
return 0;
|
823
|
+
}
|
824
|
+
return -1;
|
825
|
+
}
|
613
826
|
|
614
827
|
int plthook_enum(plthook_t *plthook, unsigned int *pos, const char **name_out, void ***addr_out)
|
615
828
|
{
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
|
829
|
+
return plthook_enum_with_prot(plthook, pos, name_out, addr_out, NULL);
|
830
|
+
}
|
831
|
+
|
832
|
+
int plthook_enum_with_prot(plthook_t *plthook, unsigned int *pos, const char **name_out, void ***addr_out, int *prot)
|
833
|
+
{
|
834
|
+
while (*pos < plthook->rela_plt_cnt) {
|
835
|
+
const Elf_Plt_Rel *plt = plthook->rela_plt + *pos;
|
836
|
+
int rv = check_rel(plthook, plt, R_JUMP_SLOT, name_out, addr_out);
|
837
|
+
(*pos)++;
|
838
|
+
if (rv >= 0) {
|
839
|
+
if (rv == 0 && prot != NULL) {
|
840
|
+
*prot = plthook_get_mem_prot(plthook, *addr_out);
|
625
841
|
}
|
626
|
-
|
627
|
-
*addr_out = (void**)(plthook->plt_addr_base + plt->r_offset);
|
628
|
-
(*pos)++;
|
629
|
-
return 0;
|
842
|
+
return rv;
|
630
843
|
}
|
844
|
+
}
|
845
|
+
#ifdef R_GLOBAL_DATA
|
846
|
+
while (*pos < plthook->rela_plt_cnt + plthook->rela_dyn_cnt) {
|
847
|
+
const Elf_Plt_Rel *plt = plthook->rela_dyn + (*pos - plthook->rela_plt_cnt);
|
848
|
+
int rv = check_rel(plthook, plt, R_GLOBAL_DATA, name_out, addr_out);
|
631
849
|
(*pos)++;
|
850
|
+
if (rv >= 0) {
|
851
|
+
if (rv == 0 && prot != NULL) {
|
852
|
+
*prot = plthook_get_mem_prot(plthook, *addr_out);
|
853
|
+
}
|
854
|
+
return rv;
|
855
|
+
}
|
632
856
|
}
|
857
|
+
#endif
|
633
858
|
*name_out = NULL;
|
634
859
|
*addr_out = NULL;
|
635
860
|
return EOF;
|
@@ -650,26 +875,26 @@ int plthook_replace(plthook_t *plthook, const char *funcname, void *funcaddr, vo
|
|
650
875
|
while ((rv = plthook_enum(plthook, &pos, &name, &addr)) == 0) {
|
651
876
|
if (strncmp(name, funcname, funcnamelen) == 0) {
|
652
877
|
if (name[funcnamelen] == '\0' || name[funcnamelen] == '@') {
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
657
|
-
|
658
|
-
|
659
|
-
|
878
|
+
int prot = plthook_get_mem_prot(plthook, addr);
|
879
|
+
if (prot == 0) {
|
880
|
+
set_errmsg("Could not get the process memory permission at %p",
|
881
|
+
ALIGN_ADDR(addr));
|
882
|
+
return PLTHOOK_INTERNAL_ERROR;
|
883
|
+
}
|
884
|
+
if (!(prot & PROT_WRITE)) {
|
885
|
+
if (mprotect(ALIGN_ADDR(addr), page_size, PROT_READ | PROT_WRITE) != 0) {
|
886
|
+
set_errmsg("Could not change the process memory permission at %p: %s",
|
887
|
+
ALIGN_ADDR(addr), strerror(errno));
|
660
888
|
return PLTHOOK_INTERNAL_ERROR;
|
661
889
|
}
|
662
890
|
}
|
663
|
-
#endif
|
664
891
|
if (oldfunc) {
|
665
892
|
*oldfunc = *addr;
|
666
893
|
}
|
667
894
|
*addr = funcaddr;
|
668
|
-
|
669
|
-
|
670
|
-
mprotect(maddr, page_size, PROT_READ);
|
895
|
+
if (!(prot & PROT_WRITE)) {
|
896
|
+
mprotect(ALIGN_ADDR(addr), page_size, prot);
|
671
897
|
}
|
672
|
-
#endif
|
673
898
|
return 0;
|
674
899
|
}
|
675
900
|
}
|