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.
@@ -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,82 @@
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
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 *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;
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
- #endif
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
- #ifdef SUPPORT_RELRO
196
- static int set_relro_members(plthook_t *plthook, struct link_map *lmap);
197
- #endif
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 __linux__
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 SUPPORT_RELRO
310
- #if defined __linux__
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
- fp = fopen("/proc/self/maps", "r");
317
- if (fp == NULL) {
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
- *err = PLTHOOK_INTERNAL_ERROR;
320
- return NULL;
426
+ return -1;
321
427
  }
322
- while (fgets(buf, PATH_MAX, fp) != NULL) {
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 offset = 0;
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 %*s %*x %*x:%*x %*u %n", &start, &end, &offset);
327
- if (offset == 0) {
455
+ if (sscanf(buf, "%lx-%lx %4s", &start, &end, perms) != 3) {
328
456
  continue;
329
457
  }
330
- if (start < addr && addr < end) {
331
- char *p = buf + offset;
332
- while (*p == ' ') {
333
- p++;
334
- }
335
- if (*p != '/') {
336
- continue;
337
- }
338
- p[strlen(p) - 1] = '\0'; /* remove '\n' */
339
- fclose(fp);
340
- return p;
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
- static const char *get_mapped_file(const void *address, char *buf, int *err)
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
- uint64_t addr = (uint64_t)address;
352
- struct kinfo_vmentry *top;
353
- int i, cnt;
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
- free(top);
371
- set_errmsg("Could not find a mapped file reagion containing %p", address);
372
- *err = PLTHOOK_INTERNAL_ERROR;
373
- return NULL;
495
+ iter->idx = 0;
496
+ return 0;
374
497
  }
375
- #else
376
- static const char *get_mapped_file(const void *address, char *buf, int *err)
498
+
499
+ static int mem_prot_next(mem_prot_iter_t *iter, mem_prot_t *mem_prot)
377
500
  {
378
- set_errmsg("Could not find a mapped file reagion containing %p", address);
379
- *err = PLTHOOK_INTERNAL_ERROR;
380
- return NULL;
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 int set_relro_members(plthook_t *plthook, struct link_map *lmap)
520
+ static void mem_prot_end(mem_prot_iter_t *iter)
385
521
  {
386
- char fnamebuf[PATH_MAX];
387
- const char *fname;
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
- Elf_Ehdr ehdr;
390
- Elf_Half idx;
391
- int rv;
529
+ prmap_t maps[20];
530
+ size_t idx;
531
+ size_t num;
532
+ };
392
533
 
393
- if (lmap->l_name[0] == '/') {
394
- fname = lmap->l_name;
395
- } else {
396
- int err;
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
- fname = get_mapped_file(plthook->dynstr, fnamebuf, &err);
399
- if (fname == NULL) {
400
- return err;
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
- fp = fopen(fname, "r");
404
- if (fp == NULL) {
405
- set_errmsg("failed to open %s", fname);
406
- return PLTHOOK_INTERNAL_ERROR;
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 (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;
563
+ if (map->pr_mflags & MA_WRITE) {
564
+ mem_prot->prot |= PROT_WRITE;
412
565
  }
413
- rv = check_elf_header(&ehdr);
414
- if (rv != 0) {
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
- 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;
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
- int rv = check_elf_header(ehdr);
451
- if (rv != 0) {
452
- return rv;
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
- 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 */
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
- 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;
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
- dyn = find_dyn_by_tag(lmap->l_ld, total_size_tag);
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 0x%x", total_size_tag);
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, elem_size_tag);
681
+ dyn = find_dyn_by_tag(lmap->l_ld, PLT_DT_RELENT);
536
682
  if (dyn == NULL) {
537
- set_errmsg("failed to find 0x%x", elem_size_tag);
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.plt_cnt = total_size / elem_size;
542
- #endif
687
+ plthook.rela_dyn_cnt = total_size / elem_size;
543
688
  }
689
+ #endif
544
690
 
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
- }
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
- 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;
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
- *name_out = plthook->dynstr + idx;
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
- #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));
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
- #ifdef SUPPORT_RELRO
669
- if (maddr != NULL) {
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
  }