ruby-oci8 2.2.12 → 2.2.13

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.
@@ -1,12 +1,12 @@
1
1
  /* -*- indent-tabs-mode: nil -*-
2
2
  *
3
- * plthook_elf.c -- implemention of plthook for ELF format
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-2016 Kubo Takehiro <kubo@jiubao.org>
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 Elf_Plt_Rel Elf_Rel
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 Elf_Plt_Rel Elf_Rela
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 Elf_Plt_Rel Elf_Rela
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 Elf_Plt_Rel Elf_Rela
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,65 @@
162
187
  #endif
163
188
  #endif /* __LP64__ */
164
189
 
165
- #if defined(PT_GNU_RELRO) && !defined(__sun)
166
- #define SUPPORT_RELRO /* RELRO (RELocation Read-Only) */
167
- #if !defined(DF_1_NOW) && defined(DF_1_BIND_NOW)
168
- #define DF_1_NOW DF_1_BIND_NOW
169
- #endif
170
- #endif
171
-
172
190
  struct plthook {
173
191
  const Elf_Sym *dynsym;
174
192
  const char *dynstr;
175
193
  size_t dynstr_size;
176
194
  const char *plt_addr_base;
177
- const Elf_Plt_Rel *plt;
178
- size_t plt_cnt;
179
- Elf_Xword r_type;
180
- #ifdef SUPPORT_RELRO
181
- const char *relro_start;
182
- const char *relro_end;
195
+ const Elf_Plt_Rel *rela_plt;
196
+ size_t rela_plt_cnt;
197
+ #ifdef R_GLOBAL_DATA
198
+ const Elf_Plt_Rel *rela_dyn;
199
+ size_t rela_dyn_cnt;
183
200
  #endif
184
201
  };
185
202
 
186
203
  static char errmsg[512];
187
-
188
- #ifdef SUPPORT_RELRO
189
204
  static size_t page_size;
190
- #endif
205
+ #define ALIGN_ADDR(addr) ((void*)((size_t)(addr) & ~(page_size - 1)))
191
206
 
192
207
  static int plthook_open_executable(plthook_t **plthook_out);
193
208
  static int plthook_open_shared_library(plthook_t **plthook_out, const char *filename);
194
209
  static const Elf_Dyn *find_dyn_by_tag(const Elf_Dyn *dyn, Elf_Sxword tag);
195
- #ifdef SUPPORT_RELRO
196
- static int set_relro_members(plthook_t *plthook, struct link_map *lmap);
197
- #endif
198
210
  static int plthook_open_real(plthook_t **plthook_out, struct link_map *lmap);
211
+ #if defined __FreeBSD__ || defined __sun
199
212
  static int check_elf_header(const Elf_Ehdr *ehdr);
213
+ #endif
200
214
  static void set_errmsg(const char *fmt, ...) __attribute__((__format__ (__printf__, 1, 2)));
201
215
 
216
+ #if defined __ANDROID__ || defined __UCLIBC__
217
+ struct dl_iterate_data {
218
+ char* addr;
219
+ struct link_map lmap;
220
+ };
221
+
222
+ static int dl_iterate_cb(struct dl_phdr_info *info, size_t size, void *cb_data)
223
+ {
224
+ struct dl_iterate_data *data = (struct dl_iterate_data*)cb_data;
225
+ Elf_Half idx = 0;
226
+
227
+ for (idx = 0; idx < info->dlpi_phnum; ++idx) {
228
+ const Elf_Phdr *phdr = &info->dlpi_phdr[idx];
229
+ char* base = (char*)info->dlpi_addr + phdr->p_vaddr;
230
+ if (base <= data->addr && data->addr < base + phdr->p_memsz) {
231
+ break;
232
+ }
233
+ }
234
+ if (idx == info->dlpi_phnum) {
235
+ return 0;
236
+ }
237
+ for (idx = 0; idx < info->dlpi_phnum; ++idx) {
238
+ const Elf_Phdr *phdr = &info->dlpi_phdr[idx];
239
+ if (phdr->p_type == PT_DYNAMIC) {
240
+ data->lmap.l_addr = info->dlpi_addr;
241
+ data->lmap.l_ld = (Elf_Dyn*)(info->dlpi_addr + phdr->p_vaddr);
242
+ return 1;
243
+ }
244
+ }
245
+ return 0;
246
+ }
247
+ #endif
248
+
202
249
  int plthook_open(plthook_t **plthook_out, const char *filename)
203
250
  {
204
251
  *plthook_out = NULL;
@@ -211,6 +258,27 @@ int plthook_open(plthook_t **plthook_out, const char *filename)
211
258
 
212
259
  int plthook_open_by_handle(plthook_t **plthook_out, void *hndl)
213
260
  {
261
+ #if defined __ANDROID__ || defined __UCLIBC__
262
+ const static char *symbols[] = {
263
+ "__INIT_ARRAY__",
264
+ "_end",
265
+ "_start"
266
+ };
267
+ size_t i;
268
+
269
+ if (hndl == NULL) {
270
+ set_errmsg("NULL handle");
271
+ return PLTHOOK_FILE_NOT_FOUND;
272
+ }
273
+ for (i = 0; i < sizeof(symbols)/sizeof(symbols[0]); i++) {
274
+ char *addr = dlsym(hndl, symbols[i]);
275
+ if (addr != NULL) {
276
+ return plthook_open_by_address(plthook_out, addr - 1);
277
+ }
278
+ }
279
+ set_errmsg("Could not find an address in the specified handle.");
280
+ return PLTHOOK_INTERNAL_ERROR;
281
+ #else
214
282
  struct link_map *lmap = NULL;
215
283
 
216
284
  if (hndl == NULL) {
@@ -222,12 +290,22 @@ int plthook_open_by_handle(plthook_t **plthook_out, void *hndl)
222
290
  return PLTHOOK_FILE_NOT_FOUND;
223
291
  }
224
292
  return plthook_open_real(plthook_out, lmap);
293
+ #endif
225
294
  }
226
295
 
227
296
  int plthook_open_by_address(plthook_t **plthook_out, void *address)
228
297
  {
229
298
  #if defined __FreeBSD__
230
299
  return PLTHOOK_NOT_IMPLEMENTED;
300
+ #elif defined __ANDROID__ || defined __UCLIBC__
301
+ struct dl_iterate_data data = {0,};
302
+ data.addr = address;
303
+ dl_iterate_phdr(dl_iterate_cb, &data);
304
+ if (data.lmap.l_ld == NULL) {
305
+ set_errmsg("Could not find memory region containing address %p", address);
306
+ return PLTHOOK_INTERNAL_ERROR;
307
+ }
308
+ return plthook_open_real(plthook_out, &data.lmap);
231
309
  #else
232
310
  Dl_info info;
233
311
  struct link_map *lmap = NULL;
@@ -243,7 +321,9 @@ int plthook_open_by_address(plthook_t **plthook_out, void *address)
243
321
 
244
322
  static int plthook_open_executable(plthook_t **plthook_out)
245
323
  {
246
- #if defined __linux__
324
+ #if defined __ANDROID__ || defined __UCLIBC__
325
+ return plthook_open_shared_library(plthook_out, NULL);
326
+ #elif defined __linux__
247
327
  return plthook_open_real(plthook_out, _r_debug.r_map);
248
328
  #elif defined __sun
249
329
  const char *auxv_file = "/proc/self/auxv";
@@ -280,12 +360,21 @@ static int plthook_open_executable(plthook_t **plthook_out)
280
360
  static int plthook_open_shared_library(plthook_t **plthook_out, const char *filename)
281
361
  {
282
362
  void *hndl = dlopen(filename, RTLD_LAZY | RTLD_NOLOAD);
363
+ #if defined __ANDROID__ || defined __UCLIBC__
364
+ int rv;
365
+ #else
283
366
  struct link_map *lmap = NULL;
367
+ #endif
284
368
 
285
369
  if (hndl == NULL) {
286
370
  set_errmsg("dlopen error: %s", dlerror());
287
371
  return PLTHOOK_FILE_NOT_FOUND;
288
372
  }
373
+ #if defined __ANDROID__ || defined __UCLIBC__
374
+ rv = plthook_open_by_handle(plthook_out, hndl);
375
+ dlclose(hndl);
376
+ return rv;
377
+ #else
289
378
  if (dlinfo(hndl, RTLD_DI_LINKMAP, &lmap) != 0) {
290
379
  set_errmsg("dlinfo error");
291
380
  dlclose(hndl);
@@ -293,6 +382,7 @@ static int plthook_open_shared_library(plthook_t **plthook_out, const char *file
293
382
  }
294
383
  dlclose(hndl);
295
384
  return plthook_open_real(plthook_out, lmap);
385
+ #endif
296
386
  }
297
387
 
298
388
  static const Elf_Dyn *find_dyn_by_tag(const Elf_Dyn *dyn, Elf_Sxword tag)
@@ -306,47 +396,79 @@ static const Elf_Dyn *find_dyn_by_tag(const Elf_Dyn *dyn, Elf_Sxword tag)
306
396
  return NULL;
307
397
  }
308
398
 
309
- #ifdef SUPPORT_RELRO
310
- #if defined __linux__
311
- static const char *get_mapped_file(const void *address, char *buf, int *err)
399
+ #ifdef __linux__
400
+ static int get_memory_permission(void *address)
312
401
  {
313
402
  unsigned long addr = (unsigned long)address;
314
403
  FILE *fp;
404
+ char buf[PATH_MAX];
405
+ char perms[5];
406
+ int bol = 1;
315
407
 
316
408
  fp = fopen("/proc/self/maps", "r");
317
409
  if (fp == NULL) {
318
410
  set_errmsg("failed to open /proc/self/maps");
319
- *err = PLTHOOK_INTERNAL_ERROR;
320
- return NULL;
411
+ return 0;
321
412
  }
322
413
  while (fgets(buf, PATH_MAX, fp) != NULL) {
323
414
  unsigned long start, end;
324
- int offset = 0;
415
+ int eol = (strchr(buf, '\n') != NULL);
416
+ if (bol) {
417
+ /* The fgets reads from the beginning of a line. */
418
+ if (!eol) {
419
+ /* The next fgets reads from the middle of the same line. */
420
+ bol = 0;
421
+ }
422
+ } else {
423
+ /* The fgets reads from the middle of a line. */
424
+ if (eol) {
425
+ /* The next fgets reads from the beginning of a line. */
426
+ bol = 1;
427
+ }
428
+ continue;
429
+ }
325
430
 
326
- sscanf(buf, "%lx-%lx %*s %*x %*x:%*x %*u %n", &start, &end, &offset);
327
- if (offset == 0) {
431
+ if (sscanf(buf, "%lx-%lx %4s", &start, &end, perms) != 3) {
328
432
  continue;
329
433
  }
330
- if (start < addr && addr < end) {
331
- char *p = buf + offset;
332
- while (*p == ' ') {
333
- p++;
434
+ if (start <= addr && addr < end) {
435
+ int prot = 0;
436
+ if (perms[0] == 'r') {
437
+ prot |= PROT_READ;
438
+ } else if (perms[0] != '-') {
439
+ goto unknown_perms;
334
440
  }
335
- if (*p != '/') {
336
- continue;
441
+ if (perms[1] == 'w') {
442
+ prot |= PROT_WRITE;
443
+ } else if (perms[1] != '-') {
444
+ goto unknown_perms;
445
+ }
446
+ if (perms[2] == 'x') {
447
+ prot |= PROT_EXEC;
448
+ } else if (perms[2] != '-') {
449
+ goto unknown_perms;
450
+ }
451
+ if (perms[3] != 'p') {
452
+ goto unknown_perms;
453
+ }
454
+ if (perms[4] != '\0') {
455
+ perms[4] = '\0';
456
+ goto unknown_perms;
337
457
  }
338
- p[strlen(p) - 1] = '\0'; /* remove '\n' */
339
458
  fclose(fp);
340
- return p;
459
+ return prot;
341
460
  }
342
461
  }
343
462
  fclose(fp);
344
- set_errmsg("Could not find a mapped file reagion containing %p", address);
345
- *err = PLTHOOK_INTERNAL_ERROR;
346
- return NULL;
463
+ set_errmsg("Could not find memory region containing %p", (void*)addr);
464
+ return 0;
465
+ unknown_perms:
466
+ fclose(fp);
467
+ set_errmsg("Unexcepted memory permission %s at %p", perms, (void*)addr);
468
+ return 0;
347
469
  }
348
470
  #elif defined __FreeBSD__
349
- static const char *get_mapped_file(const void *address, char *buf, int *err)
471
+ static int get_memory_permission(void *address)
350
472
  {
351
473
  uint64_t addr = (uint64_t)address;
352
474
  struct kinfo_vmentry *top;
@@ -354,87 +476,78 @@ static const char *get_mapped_file(const void *address, char *buf, int *err)
354
476
 
355
477
  top = kinfo_getvmmap(getpid(), &cnt);
356
478
  if (top == NULL) {
357
- fprintf(stderr, "failed to call kinfo_getvmmap()\n");
358
- *err = PLTHOOK_INTERNAL_ERROR;
359
- return NULL;
479
+ set_errmsg("failed to call kinfo_getvmmap()\n");
480
+ return 0;
360
481
  }
361
482
  for (i = 0; i < cnt; i++) {
362
483
  struct kinfo_vmentry *kve = top + i;
363
484
 
364
- if (kve->kve_start < addr && addr < kve->kve_end) {
365
- strncpy(buf, kve->kve_path, PATH_MAX);
485
+ if (kve->kve_start <= addr && addr < kve->kve_end) {
486
+ int prot = 0;
487
+ if (kve->kve_protection & KVME_PROT_READ) {
488
+ prot |= PROT_READ;
489
+ }
490
+ if (kve->kve_protection & KVME_PROT_WRITE) {
491
+ prot |= PROT_WRITE;
492
+ }
493
+ if (kve->kve_protection & KVME_PROT_EXEC) {
494
+ prot |= PROT_EXEC;
495
+ }
496
+ if (prot == 0) {
497
+ set_errmsg("Unknown kve_protection 0x%x at %p", kve->kve_protection, (void*)addr);
498
+ }
366
499
  free(top);
367
- return buf;
500
+ return prot;
368
501
  }
369
502
  }
370
503
  free(top);
371
- set_errmsg("Could not find a mapped file reagion containing %p", address);
372
- *err = PLTHOOK_INTERNAL_ERROR;
373
- return NULL;
374
- }
375
- #else
376
- static const char *get_mapped_file(const void *address, char *buf, int *err)
377
- {
378
- set_errmsg("Could not find a mapped file reagion containing %p", address);
379
- *err = PLTHOOK_INTERNAL_ERROR;
380
- return NULL;
504
+ set_errmsg("Could not find memory region containing %p", (void*)addr);
505
+ return 0;
381
506
  }
382
- #endif
383
-
384
- static int set_relro_members(plthook_t *plthook, struct link_map *lmap)
507
+ #elif defined(__sun)
508
+ #define NUM_MAPS 20
509
+ static int get_memory_permission(void *address)
385
510
  {
386
- char fnamebuf[PATH_MAX];
387
- const char *fname;
511
+ unsigned long addr = (unsigned long)address;
388
512
  FILE *fp;
389
- Elf_Ehdr ehdr;
390
- Elf_Half idx;
391
- int rv;
392
-
393
- if (lmap->l_name[0] == '/') {
394
- fname = lmap->l_name;
395
- } else {
396
- int err;
513
+ prmap_t maps[NUM_MAPS];
514
+ size_t num;
397
515
 
398
- fname = get_mapped_file(plthook->dynstr, fnamebuf, &err);
399
- if (fname == NULL) {
400
- return err;
401
- }
402
- }
403
- fp = fopen(fname, "r");
516
+ fp = fopen("/proc/self/map", "r");
404
517
  if (fp == NULL) {
405
- set_errmsg("failed to open %s", fname);
406
- return PLTHOOK_INTERNAL_ERROR;
407
- }
408
- if (fread(&ehdr, sizeof(ehdr), 1, fp) != 1) {
409
- set_errmsg("failed to read the ELF header.");
410
- fclose(fp);
411
- return PLTHOOK_INVALID_FILE_FORMAT;
412
- }
413
- rv = check_elf_header(&ehdr);
414
- if (rv != 0) {
415
- fclose(fp);
416
- return rv;
417
- }
418
-
419
- fseek(fp, ehdr.e_phoff, SEEK_SET);
420
-
421
- for (idx = 0; idx < ehdr.e_phnum; idx++) {
422
- Elf_Phdr phdr;
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;
518
+ set_errmsg("failed to open /proc/self/map");
519
+ return 0;
520
+ }
521
+ while ((num = fread(maps, sizeof(prmap_t), NUM_MAPS, fp)) > 0) {
522
+ size_t i;
523
+ for (i = 0; i < num; i++) {
524
+ prmap_t *map = &maps[i];
525
+
526
+ if (map->pr_vaddr <= addr && addr < map->pr_vaddr + map->pr_size) {
527
+ int prot = 0;
528
+ if (map->pr_mflags & MA_READ) {
529
+ prot |= PROT_READ;
530
+ }
531
+ if (map->pr_mflags & MA_WRITE) {
532
+ prot |= PROT_WRITE;
533
+ }
534
+ if (map->pr_mflags & MA_EXEC) {
535
+ prot |= PROT_EXEC;
536
+ }
537
+ if (prot == 0) {
538
+ set_errmsg("Unknown pr_mflags 0x%x at %p", map->pr_mflags, (void*)addr);
539
+ }
540
+ fclose(fp);
541
+ return prot;
542
+ }
433
543
  }
434
544
  }
435
545
  fclose(fp);
546
+ set_errmsg("Could not find memory region containing %p", (void*)addr);
436
547
  return 0;
437
548
  }
549
+ #else
550
+ #error Unsupported platform
438
551
  #endif
439
552
 
440
553
  static int plthook_open_real(plthook_t **plthook_out, struct link_map *lmap)
@@ -443,13 +556,26 @@ static int plthook_open_real(plthook_t **plthook_out, struct link_map *lmap)
443
556
  const Elf_Dyn *dyn;
444
557
  const char *dyn_addr_base = NULL;
445
558
 
559
+ if (page_size == 0) {
560
+ page_size = sysconf(_SC_PAGESIZE);
561
+ }
562
+
446
563
  #if defined __linux__
447
564
  plthook.plt_addr_base = (char*)lmap->l_addr;
565
+ #if defined __riscv
566
+ const Elf_Ehdr *ehdr = (const Elf_Ehdr*)lmap->l_addr;
567
+ if (ehdr->e_type == ET_DYN) {
568
+ dyn_addr_base = (const char*)lmap->l_addr;
569
+ }
570
+ #endif
571
+ #if defined __ANDROID__ || defined __UCLIBC__
572
+ dyn_addr_base = (const char*)lmap->l_addr;
573
+ #endif
448
574
  #elif defined __FreeBSD__ || defined __sun
449
575
  const Elf_Ehdr *ehdr = (const Elf_Ehdr*)lmap->l_addr;
450
- int rv = check_elf_header(ehdr);
451
- if (rv != 0) {
452
- return rv;
576
+ int rv_ = check_elf_header(ehdr);
577
+ if (rv_ != 0) {
578
+ return rv_;
453
579
  }
454
580
  if (ehdr->e_type == ET_DYN) {
455
581
  dyn_addr_base = (const char*)lmap->l_addr;
@@ -496,62 +622,48 @@ static int plthook_open_real(plthook_t **plthook_out, struct link_map *lmap)
496
622
 
497
623
  /* get .rela.plt or .rel.plt section */
498
624
  dyn = find_dyn_by_tag(lmap->l_ld, DT_JMPREL);
499
- plthook.r_type = R_JUMP_SLOT;
500
- #ifdef PLT_DT_REL
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 */
625
+ if (dyn != NULL) {
626
+ plthook.rela_plt = (const Elf_Plt_Rel *)(dyn_addr_base + dyn->d_un.d_ptr);
515
627
  dyn = find_dyn_by_tag(lmap->l_ld, DT_PLTRELSZ);
516
628
  if (dyn == NULL) {
517
629
  set_errmsg("failed to find DT_PLTRELSZ");
518
630
  return PLTHOOK_INTERNAL_ERROR;
519
631
  }
520
-
521
- plthook.plt_cnt = dyn->d_un.d_val / sizeof(Elf_Plt_Rel);
522
- #ifdef PLT_DT_REL
523
- } else {
524
- int total_size_tag = PLT_DT_REL == DT_RELA ? DT_RELASZ : DT_RELSZ;
525
- int elem_size_tag = PLT_DT_REL == DT_RELA ? DT_RELAENT : DT_RELENT;
632
+ plthook.rela_plt_cnt = dyn->d_un.d_val / sizeof(Elf_Plt_Rel);
633
+ }
634
+ #ifdef R_GLOBAL_DATA
635
+ /* get .rela.dyn or .rel.dyn section */
636
+ dyn = find_dyn_by_tag(lmap->l_ld, PLT_DT_REL);
637
+ if (dyn != NULL) {
526
638
  size_t total_size, elem_size;
527
639
 
528
- dyn = find_dyn_by_tag(lmap->l_ld, total_size_tag);
640
+ plthook.rela_dyn = (const Elf_Plt_Rel *)(dyn_addr_base + dyn->d_un.d_ptr);
641
+ dyn = find_dyn_by_tag(lmap->l_ld, PLT_DT_RELSZ);
529
642
  if (dyn == NULL) {
530
- set_errmsg("failed to find 0x%x", total_size_tag);
643
+ set_errmsg("failed to find PLT_DT_RELSZ");
531
644
  return PLTHOOK_INTERNAL_ERROR;
532
645
  }
533
646
  total_size = dyn->d_un.d_ptr;
534
647
 
535
- dyn = find_dyn_by_tag(lmap->l_ld, elem_size_tag);
648
+ dyn = find_dyn_by_tag(lmap->l_ld, PLT_DT_RELENT);
536
649
  if (dyn == NULL) {
537
- set_errmsg("failed to find 0x%x", elem_size_tag);
650
+ set_errmsg("failed to find PLT_DT_RELENT");
538
651
  return PLTHOOK_INTERNAL_ERROR;
539
652
  }
540
653
  elem_size = dyn->d_un.d_ptr;
541
- plthook.plt_cnt = total_size / elem_size;
542
- #endif
654
+ plthook.rela_dyn_cnt = total_size / elem_size;
543
655
  }
656
+ #endif
544
657
 
545
- #ifdef SUPPORT_RELRO
546
- dyn = find_dyn_by_tag(lmap->l_ld, DT_FLAGS_1);
547
- if (dyn != NULL && (dyn->d_un.d_val & DF_1_NOW)) {
548
- int rv = set_relro_members(&plthook, lmap);
549
- if (rv != 0) {
550
- return rv;
551
- }
552
- if (page_size == 0) {
553
- page_size = sysconf(_SC_PAGESIZE);
554
- }
658
+ #ifdef R_GLOBAL_DATA
659
+ if (plthook.rela_plt == NULL && plthook.rela_dyn == NULL) {
660
+ set_errmsg("failed to find either of DT_JMPREL and DT_REL");
661
+ return PLTHOOK_INTERNAL_ERROR;
662
+ }
663
+ #else
664
+ if (plthook.rela_plt == NULL) {
665
+ set_errmsg("failed to find DT_JMPREL");
666
+ return PLTHOOK_INTERNAL_ERROR;
555
667
  }
556
668
  #endif
557
669
 
@@ -564,6 +676,7 @@ static int plthook_open_real(plthook_t **plthook_out, struct link_map *lmap)
564
676
  return 0;
565
677
  }
566
678
 
679
+ #if defined __FreeBSD__ || defined __sun
567
680
  static int check_elf_header(const Elf_Ehdr *ehdr)
568
681
  {
569
682
  static const unsigned short s = 1;
@@ -610,26 +723,44 @@ static int check_elf_header(const Elf_Ehdr *ehdr)
610
723
  }
611
724
  return 0;
612
725
  }
726
+ #endif
727
+
728
+ static int check_rel(const plthook_t *plthook, const Elf_Plt_Rel *plt, Elf_Xword r_type, const char **name_out, void ***addr_out)
729
+ {
730
+ if (ELF_R_TYPE(plt->r_info) == r_type) {
731
+ size_t idx = ELF_R_SYM(plt->r_info);
732
+ idx = plthook->dynsym[idx].st_name;
733
+ if (idx + 1 > plthook->dynstr_size) {
734
+ set_errmsg("too big section header string table index: %" SIZE_T_FMT, idx);
735
+ return PLTHOOK_INVALID_FILE_FORMAT;
736
+ }
737
+ *name_out = plthook->dynstr + idx;
738
+ *addr_out = (void**)(plthook->plt_addr_base + plt->r_offset);
739
+ return 0;
740
+ }
741
+ return -1;
742
+ }
613
743
 
614
744
  int plthook_enum(plthook_t *plthook, unsigned int *pos, const char **name_out, void ***addr_out)
615
745
  {
616
- while (*pos < plthook->plt_cnt) {
617
- const Elf_Plt_Rel *plt = plthook->plt + *pos;
618
- if (ELF_R_TYPE(plt->r_info) == plthook->r_type) {
619
- size_t idx = ELF_R_SYM(plt->r_info);
620
-
621
- idx = plthook->dynsym[idx].st_name;
622
- if (idx + 1 > plthook->dynstr_size) {
623
- set_errmsg("too big section header string table index: %" SIZE_T_FMT, idx);
624
- return PLTHOOK_INVALID_FILE_FORMAT;
625
- }
626
- *name_out = plthook->dynstr + idx;
627
- *addr_out = (void**)(plthook->plt_addr_base + plt->r_offset);
628
- (*pos)++;
629
- return 0;
746
+ while (*pos < plthook->rela_plt_cnt) {
747
+ const Elf_Plt_Rel *plt = plthook->rela_plt + *pos;
748
+ int rv = check_rel(plthook, plt, R_JUMP_SLOT, name_out, addr_out);
749
+ (*pos)++;
750
+ if (rv >= 0) {
751
+ return rv;
630
752
  }
753
+ }
754
+ #ifdef R_GLOBAL_DATA
755
+ while (*pos < plthook->rela_plt_cnt + plthook->rela_dyn_cnt) {
756
+ const Elf_Plt_Rel *plt = plthook->rela_dyn + (*pos - plthook->rela_plt_cnt);
757
+ int rv = check_rel(plthook, plt, R_GLOBAL_DATA, name_out, addr_out);
631
758
  (*pos)++;
759
+ if (rv >= 0) {
760
+ return rv;
761
+ }
632
762
  }
763
+ #endif
633
764
  *name_out = NULL;
634
765
  *addr_out = NULL;
635
766
  return EOF;
@@ -650,26 +781,24 @@ int plthook_replace(plthook_t *plthook, const char *funcname, void *funcaddr, vo
650
781
  while ((rv = plthook_enum(plthook, &pos, &name, &addr)) == 0) {
651
782
  if (strncmp(name, funcname, funcnamelen) == 0) {
652
783
  if (name[funcnamelen] == '\0' || name[funcnamelen] == '@') {
653
- #ifdef SUPPORT_RELRO
654
- void *maddr = NULL;
655
- if (plthook->relro_start <= (char*)addr && (char*)addr < plthook->relro_end) {
656
- maddr = (void*)((size_t)addr & ~(page_size - 1));
657
- if (mprotect(maddr, page_size, PROT_READ | PROT_WRITE) != 0) {
658
- set_errmsg("Could not change the process memory protection at %p: %s",
659
- maddr, strerror(errno));
784
+ int prot = get_memory_permission(addr);
785
+ if (prot == 0) {
786
+ return PLTHOOK_INTERNAL_ERROR;
787
+ }
788
+ if (!(prot & PROT_WRITE)) {
789
+ if (mprotect(ALIGN_ADDR(addr), page_size, PROT_READ | PROT_WRITE) != 0) {
790
+ set_errmsg("Could not change the process memory permission at %p: %s",
791
+ ALIGN_ADDR(addr), strerror(errno));
660
792
  return PLTHOOK_INTERNAL_ERROR;
661
793
  }
662
794
  }
663
- #endif
664
795
  if (oldfunc) {
665
796
  *oldfunc = *addr;
666
797
  }
667
798
  *addr = funcaddr;
668
- #ifdef SUPPORT_RELRO
669
- if (maddr != NULL) {
670
- mprotect(maddr, page_size, PROT_READ);
799
+ if (!(prot & PROT_WRITE)) {
800
+ mprotect(ALIGN_ADDR(addr), page_size, prot);
671
801
  }
672
- #endif
673
802
  return 0;
674
803
  }
675
804
  }