ruby-oci8 2.2.12 → 2.2.13

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
  }