ruby-oci8 2.2.4.1 → 2.2.11

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.
Files changed (62) hide show
  1. checksums.yaml +7 -0
  2. data/ChangeLog +311 -1
  3. data/NEWS +278 -46
  4. data/README.md +5 -2
  5. data/dist-files +8 -4
  6. data/docs/bind-array-to-in_cond.md +1 -1
  7. data/docs/install-instant-client.md +2 -1
  8. data/docs/install-on-osx.md +29 -116
  9. data/docs/ldap-auth-and-function-interposition.md +123 -0
  10. data/docs/number-type-mapping.md +79 -0
  11. data/ext/oci8/apiwrap.c.tmpl +2 -5
  12. data/ext/oci8/apiwrap.rb +6 -1
  13. data/ext/oci8/apiwrap.yml +34 -22
  14. data/ext/oci8/attr.c +4 -2
  15. data/ext/oci8/bind.c +366 -6
  16. data/ext/oci8/connection_pool.c +3 -3
  17. data/ext/oci8/error.c +18 -33
  18. data/ext/oci8/extconf.rb +7 -4
  19. data/ext/oci8/hook_funcs.c +128 -51
  20. data/ext/oci8/lob.c +31 -75
  21. data/ext/oci8/metadata.c +2 -2
  22. data/ext/oci8/object.c +72 -27
  23. data/ext/oci8/oci8.c +27 -119
  24. data/ext/oci8/oci8.h +21 -3
  25. data/ext/oci8/oci8lib.c +50 -37
  26. data/ext/oci8/ocihandle.c +2 -2
  27. data/ext/oci8/ocinumber.c +22 -16
  28. data/ext/oci8/oraconf.rb +130 -257
  29. data/ext/oci8/oradate.c +1 -1
  30. data/ext/oci8/plthook_elf.c +384 -300
  31. data/ext/oci8/plthook_osx.c +10 -10
  32. data/ext/oci8/stmt.c +51 -16
  33. data/ext/oci8/win32.c +4 -22
  34. data/lib/oci8/bindtype.rb +1 -15
  35. data/lib/oci8/check_load_error.rb +57 -10
  36. data/lib/oci8/cursor.rb +48 -17
  37. data/lib/oci8/metadata.rb +9 -1
  38. data/lib/oci8/object.rb +10 -0
  39. data/lib/oci8/oci8.rb +26 -25
  40. data/lib/oci8/oracle_version.rb +11 -1
  41. data/lib/oci8/version.rb +1 -1
  42. data/lib/oci8.rb +11 -4
  43. data/lib/ruby-oci8.rb +0 -3
  44. data/ruby-oci8.gemspec +2 -3
  45. data/setup.rb +11 -2
  46. data/test/README.md +37 -0
  47. data/test/config.rb +1 -1
  48. data/test/setup_test_object.sql +21 -13
  49. data/test/setup_test_package.sql +59 -0
  50. data/test/test_all.rb +1 -0
  51. data/test/test_bind_boolean.rb +99 -0
  52. data/test/test_break.rb +11 -9
  53. data/test/test_clob.rb +4 -16
  54. data/test/test_datetime.rb +8 -3
  55. data/test/test_object.rb +33 -9
  56. data/test/test_oci8.rb +169 -45
  57. data/test/test_oranumber.rb +12 -6
  58. data/test/test_package_type.rb +15 -3
  59. data/test/test_properties.rb +17 -0
  60. metadata +40 -57
  61. data/docs/osx-install-dev-tools.png +0 -0
  62. data/test/README +0 -42
@@ -36,23 +36,27 @@
36
36
  #if defined(__sun) && defined(_XOPEN_SOURCE) && !defined(__EXTENSIONS__)
37
37
  #define __EXTENSIONS__
38
38
  #endif
39
+ #if defined(__linux__) && !defined(_GNU_SOURCE)
39
40
  #define _GNU_SOURCE
41
+ #endif
40
42
  #include <stdio.h>
41
43
  #include <stdarg.h>
42
44
  #include <stdlib.h>
43
45
  #include <unistd.h>
44
46
  #include <string.h>
45
47
  #include <limits.h>
46
- #include <sys/types.h>
47
- #include <sys/stat.h>
48
48
  #include <sys/mman.h>
49
- #include <fcntl.h>
50
49
  #include <errno.h>
51
50
  #include <dlfcn.h>
52
51
  #ifdef __sun
53
- #include <procfs.h>
52
+ #include <sys/auxv.h>
54
53
  #define ELF_TARGET_ALL
55
54
  #endif /* __sun */
55
+ #ifdef __FreeBSD__
56
+ #include <sys/types.h>
57
+ #include <sys/user.h>
58
+ #include <libutil.h>
59
+ #endif
56
60
  #include <elf.h>
57
61
  #include <link.h>
58
62
  #include "plthook.h"
@@ -61,40 +65,47 @@
61
65
  #define __attribute__(arg)
62
66
  #endif
63
67
 
64
- #if defined __linux__
65
- #define ELF_OSABI ELFOSABI_SYSV
66
- #define ELF_OSABI_ALT ELFOSABI_LINUX
67
- #elif defined __sun
68
- #define ELF_OSABI ELFOSABI_SOLARIS
69
- #elif defined __FreeBSD__
70
- #define ELF_OSABI ELFOSABI_FREEBSD
71
- #if defined __i386__ && __ELF_WORD_SIZE == 64
68
+ #if defined __FreeBSD__ && defined __i386__ && __ELF_WORD_SIZE == 64
72
69
  #error 32-bit application on 64-bit OS is not supported.
73
70
  #endif
74
- #else
75
- #error unsupported OS
71
+
72
+ #if !defined(R_X86_64_JUMP_SLOT) && defined(R_X86_64_JMP_SLOT)
73
+ #define R_X86_64_JUMP_SLOT R_X86_64_JMP_SLOT
76
74
  #endif
77
75
 
78
76
  #if defined __x86_64__ || defined __x86_64
79
- #define ELF_DATA ELFDATA2LSB
80
- #define E_MACHINE EM_X86_64
81
- #ifdef R_X86_64_JUMP_SLOT
82
77
  #define R_JUMP_SLOT R_X86_64_JUMP_SLOT
83
- #else
84
- #define R_JUMP_SLOT R_X86_64_JMP_SLOT
85
- #endif
86
- #define SHT_PLT_REL SHT_RELA
87
78
  #define Elf_Plt_Rel Elf_Rela
88
- #define PLT_SECTION_NAME ".rela.plt"
79
+ #define PLT_DT_REL DT_RELA
80
+ #define R_GLOBAL_DATA R_X86_64_GLOB_DAT
89
81
  #elif defined __i386__ || defined __i386
90
- #define ELF_DATA ELFDATA2LSB
91
- #define E_MACHINE EM_386
92
82
  #define R_JUMP_SLOT R_386_JMP_SLOT
93
- #define SHT_PLT_REL SHT_REL
94
83
  #define Elf_Plt_Rel Elf_Rel
95
- #define PLT_SECTION_NAME ".rel.plt"
84
+ #define PLT_DT_REL DT_REL
85
+ #define R_GLOBAL_DATA R_386_GLOB_DAT
86
+ #elif defined __arm__ || defined __arm
87
+ #define R_JUMP_SLOT R_ARM_JUMP_SLOT
88
+ #define Elf_Plt_Rel Elf_Rel
89
+ #elif defined __aarch64__ || defined __aarch64 /* ARM64 */
90
+ #define R_JUMP_SLOT R_AARCH64_JUMP_SLOT
91
+ #define Elf_Plt_Rel Elf_Rela
92
+ #elif defined __powerpc64__
93
+ #define R_JUMP_SLOT R_PPC64_JMP_SLOT
94
+ #define Elf_Plt_Rel Elf_Rela
95
+ #elif defined __powerpc__
96
+ #define R_JUMP_SLOT R_PPC_JMP_SLOT
97
+ #define Elf_Plt_Rel Elf_Rela
98
+ #elif 0 /* disabled because not tested */ && (defined __sparcv9 || defined __sparc_v9__)
99
+ #define R_JUMP_SLOT R_SPARC_JMP_SLOT
100
+ #define Elf_Plt_Rel Elf_Rela
101
+ #elif 0 /* disabled because not tested */ && (defined __sparc || defined __sparc__)
102
+ #define R_JUMP_SLOT R_SPARC_JMP_SLOT
103
+ #define Elf_Plt_Rel Elf_Rela
104
+ #elif 0 /* disabled because not tested */ && (defined __ia64 || defined __ia64__)
105
+ #define R_JUMP_SLOT R_IA64_IPLTMSB
106
+ #define Elf_Plt_Rel Elf_Rela
96
107
  #else
97
- #error E_MACHINE is not defined.
108
+ #error unsupported OS
98
109
  #endif
99
110
 
100
111
  #if defined __LP64__
@@ -102,12 +113,16 @@
102
113
  #define ELF_CLASS ELFCLASS64
103
114
  #endif
104
115
  #define SIZE_T_FMT "lu"
116
+ #define ELF_WORD_FMT "u"
117
+ #define ELF_XWORD_FMT "lu"
118
+ #define ELF_SXWORD_FMT "ld"
105
119
  #define Elf_Half Elf64_Half
106
- #define Elf_Addr Elf64_Addr
120
+ #define Elf_Xword Elf64_Xword
121
+ #define Elf_Sxword Elf64_Sxword
107
122
  #define Elf_Ehdr Elf64_Ehdr
108
123
  #define Elf_Phdr Elf64_Phdr
109
- #define Elf_Shdr Elf64_Shdr
110
124
  #define Elf_Sym Elf64_Sym
125
+ #define Elf_Dyn Elf64_Dyn
111
126
  #define Elf_Rel Elf64_Rel
112
127
  #define Elf_Rela Elf64_Rela
113
128
  #ifndef ELF_R_SYM
@@ -121,12 +136,22 @@
121
136
  #define ELF_CLASS ELFCLASS32
122
137
  #endif
123
138
  #define SIZE_T_FMT "u"
139
+ #ifdef __sun
140
+ #define ELF_WORD_FMT "lu"
141
+ #define ELF_XWORD_FMT "lu"
142
+ #define ELF_SXWORD_FMT "ld"
143
+ #else
144
+ #define ELF_WORD_FMT "u"
145
+ #define ELF_XWORD_FMT "u"
146
+ #define ELF_SXWORD_FMT "d"
147
+ #endif
124
148
  #define Elf_Half Elf32_Half
125
- #define Elf_Addr Elf32_Addr
149
+ #define Elf_Xword Elf32_Word
150
+ #define Elf_Sxword Elf32_Sword
126
151
  #define Elf_Ehdr Elf32_Ehdr
127
152
  #define Elf_Phdr Elf32_Phdr
128
- #define Elf_Shdr Elf32_Shdr
129
153
  #define Elf_Sym Elf32_Sym
154
+ #define Elf_Dyn Elf32_Dyn
130
155
  #define Elf_Rel Elf32_Rel
131
156
  #define Elf_Rela Elf32_Rela
132
157
  #ifndef ELF_R_SYM
@@ -137,21 +162,22 @@
137
162
  #endif
138
163
  #endif /* __LP64__ */
139
164
 
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
+
140
172
  struct plthook {
141
- const char *base;
142
- const Elf_Phdr *phdr;
143
- size_t phnum;
144
- Elf_Shdr *shdr;
145
- size_t shnum;
146
- char *shstrtab;
147
- size_t shstrtab_size;
148
173
  const Elf_Sym *dynsym;
149
- size_t dynsym_cnt;
150
174
  const char *dynstr;
151
175
  size_t dynstr_size;
176
+ const char *plt_addr_base;
152
177
  const Elf_Plt_Rel *plt;
153
178
  size_t plt_cnt;
154
- #ifdef PT_GNU_RELRO
179
+ Elf_Xword r_type;
180
+ #ifdef SUPPORT_RELRO
155
181
  const char *relro_start;
156
182
  const char *relro_end;
157
183
  #endif
@@ -159,15 +185,18 @@ struct plthook {
159
185
 
160
186
  static char errmsg[512];
161
187
 
162
- #ifdef PT_GNU_RELRO
188
+ #ifdef SUPPORT_RELRO
163
189
  static size_t page_size;
164
190
  #endif
165
191
 
166
192
  static int plthook_open_executable(plthook_t **plthook_out);
167
193
  static int plthook_open_shared_library(plthook_t **plthook_out, const char *filename);
168
- static int plthook_open_real(plthook_t **plthook_out, const char *base, const char *filename);
194
+ 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
+ static int plthook_open_real(plthook_t **plthook_out, struct link_map *lmap);
169
199
  static int check_elf_header(const Elf_Ehdr *ehdr);
170
- static int find_section(plthook_t *image, const char *name, const Elf_Shdr **out);
171
200
  static void set_errmsg(const char *fmt, ...) __attribute__((__format__ (__printf__, 1, 2)));
172
201
 
173
202
  int plthook_open(plthook_t **plthook_out, const char *filename)
@@ -192,71 +221,54 @@ int plthook_open_by_handle(plthook_t **plthook_out, void *hndl)
192
221
  set_errmsg("dlinfo error");
193
222
  return PLTHOOK_FILE_NOT_FOUND;
194
223
  }
195
- if (lmap->l_addr == 0 && *lmap->l_name == 0) {
196
- return plthook_open_executable(plthook_out);
197
- }
198
- return plthook_open_real(plthook_out, (const char*)lmap->l_addr, lmap->l_name);
224
+ return plthook_open_real(plthook_out, lmap);
199
225
  }
200
226
 
201
227
  int plthook_open_by_address(plthook_t **plthook_out, void *address)
202
228
  {
229
+ #if defined __FreeBSD__
230
+ return PLTHOOK_NOT_IMPLEMENTED;
231
+ #else
203
232
  Dl_info info;
233
+ struct link_map *lmap = NULL;
204
234
 
205
235
  *plthook_out = NULL;
206
- if (dladdr(address, &info) == 0) {
236
+ if (dladdr1(address, &info, (void**)&lmap, RTLD_DL_LINKMAP) == 0) {
207
237
  set_errmsg("dladdr error");
208
238
  return PLTHOOK_FILE_NOT_FOUND;
209
239
  }
210
- return plthook_open_real(plthook_out, info.dli_fbase, info.dli_fname);
240
+ return plthook_open_real(plthook_out, lmap);
241
+ #endif
211
242
  }
212
243
 
213
244
  static int plthook_open_executable(plthook_t **plthook_out)
214
245
  {
215
246
  #if defined __linux__
216
- /* Open the main program. */
217
- char buf[128];
218
- FILE *fp = fopen("/proc/self/maps", "r");
219
- unsigned long base;
247
+ return plthook_open_real(plthook_out, _r_debug.r_map);
248
+ #elif defined __sun
249
+ const char *auxv_file = "/proc/self/auxv";
250
+ #define NUM_AUXV_CNT 10
251
+ FILE *fp = fopen(auxv_file, "r");
252
+ auxv_t auxv;
253
+ struct r_debug *r_debug = NULL;
220
254
 
221
255
  if (fp == NULL) {
222
- set_errmsg("Could not open /proc/self/maps: %s",
256
+ set_errmsg("Could not open %s: %s", auxv_file,
223
257
  strerror(errno));
224
258
  return PLTHOOK_INTERNAL_ERROR;
225
259
  }
226
- if (fgets(buf, sizeof(buf), fp) == NULL) {
227
- set_errmsg("Could not read /proc/self/maps: %s",
228
- strerror(errno));
229
- fclose(fp);
230
- return PLTHOOK_INTERNAL_ERROR;
260
+ while (fread(&auxv, sizeof(auxv_t), 1, fp) == 1) {
261
+ if (auxv.a_type == AT_SUN_LDDATA) {
262
+ r_debug = (struct r_debug *)auxv.a_un.a_ptr;
263
+ break;
264
+ }
231
265
  }
232
266
  fclose(fp);
233
- if (sscanf(buf, "%lx-%*x r-xp %*x %*x:%*x %*u ", &base) != 1) {
234
- set_errmsg("invalid /proc/self/maps format: %s", buf);
267
+ if (r_debug == NULL) {
268
+ set_errmsg("Could not find r_debug");
235
269
  return PLTHOOK_INTERNAL_ERROR;
236
270
  }
237
- return plthook_open_real(plthook_out, (const char*)base, "/proc/self/exe");
238
- #elif defined __sun
239
- prmap_t prmap;
240
- pid_t pid = getpid();
241
- char fname[128];
242
- int fd;
243
-
244
- sprintf(fname, "/proc/%d/map", pid);
245
- fd = open(fname, O_RDONLY);
246
- if (fd == -1) {
247
- set_errmsg("Could not open %s: %s", fname,
248
- strerror(errno));
249
- return PLTHOOK_INTERNAL_ERROR;
250
- }
251
- if (read(fd, &prmap, sizeof(prmap)) != sizeof(prmap)) {
252
- set_errmsg("Could not read %s: %s", fname,
253
- strerror(errno));
254
- close(fd);
255
- return PLTHOOK_INTERNAL_ERROR;
256
- }
257
- close(fd);
258
- sprintf(fname, "/proc/%d/object/a.out", pid);
259
- return plthook_open_real(plthook_out, (const char*)prmap.pr_vaddr, fname);
271
+ return plthook_open_real(plthook_out, r_debug->r_map);
260
272
  #elif defined __FreeBSD__
261
273
  return plthook_open_shared_library(plthook_out, NULL);
262
274
  #else
@@ -280,187 +292,339 @@ static int plthook_open_shared_library(plthook_t **plthook_out, const char *file
280
292
  return PLTHOOK_FILE_NOT_FOUND;
281
293
  }
282
294
  dlclose(hndl);
283
- return plthook_open_real(plthook_out, (const char*)lmap->l_addr, lmap->l_name);
295
+ return plthook_open_real(plthook_out, lmap);
284
296
  }
285
297
 
286
- static int plthook_open_real(plthook_t **plthook_out, const char *base, const char *filename)
298
+ static const Elf_Dyn *find_dyn_by_tag(const Elf_Dyn *dyn, Elf_Sxword tag)
287
299
  {
288
- const Elf_Ehdr *ehdr = (Elf_Ehdr *)base;
289
- const Elf_Shdr *shdr;
290
- size_t shdr_size;
291
- int fd = -1;
292
- off_t offset;
293
- plthook_t *plthook;
294
- int rv;
295
- #ifdef PT_GNU_RELRO
296
- size_t idx;
297
- #endif
298
-
299
- if (base == NULL) {
300
- set_errmsg("The base address is zero.");
301
- return PLTHOOK_FILE_NOT_FOUND;
300
+ while (dyn->d_tag != DT_NULL) {
301
+ if (dyn->d_tag == tag) {
302
+ return dyn;
303
+ }
304
+ dyn++;
302
305
  }
306
+ return NULL;
307
+ }
303
308
 
304
- if (filename == NULL) {
305
- set_errmsg("failed to get the file name on the disk.");
306
- return PLTHOOK_FILE_NOT_FOUND;
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;
314
+ FILE *fp;
315
+
316
+ fp = fopen("/proc/self/maps", "r");
317
+ if (fp == NULL) {
318
+ set_errmsg("failed to open /proc/self/maps");
319
+ *err = PLTHOOK_INTERNAL_ERROR;
320
+ return NULL;
307
321
  }
322
+ while (fgets(buf, PATH_MAX, fp) != NULL) {
323
+ unsigned long start, end;
324
+ int offset = 0;
308
325
 
309
- plthook = calloc(1, sizeof(plthook_t));
310
- if (plthook == NULL) {
311
- set_errmsg("failed to allocate memory: %" SIZE_T_FMT " bytes", sizeof(plthook_t));
312
- return PLTHOOK_OUT_OF_MEMORY;
326
+ sscanf(buf, "%lx-%lx %*s %*x %*x:%*x %*u %n", &start, &end, &offset);
327
+ if (offset == 0) {
328
+ continue;
329
+ }
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;
341
+ }
313
342
  }
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
+ }
348
+ #elif defined __FreeBSD__
349
+ static const char *get_mapped_file(const void *address, char *buf, int *err)
350
+ {
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
+ }
369
+ }
370
+ 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;
381
+ }
382
+ #endif
383
+
384
+ static int set_relro_members(plthook_t *plthook, struct link_map *lmap)
385
+ {
386
+ char fnamebuf[PATH_MAX];
387
+ const char *fname;
388
+ 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;
314
397
 
315
- /* sanity check */
316
- rv = check_elf_header(ehdr);
398
+ fname = get_mapped_file(plthook->dynstr, fnamebuf, &err);
399
+ if (fname == NULL) {
400
+ return err;
401
+ }
402
+ }
403
+ fp = fopen(fname, "r");
404
+ 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);
317
414
  if (rv != 0) {
318
- goto error_exit;
415
+ fclose(fp);
416
+ return rv;
319
417
  }
320
- if (ehdr->e_type == ET_DYN) {
321
- plthook->base = base;
322
- }
323
- plthook->phdr = (const Elf_Phdr *)(plthook->base + ehdr->e_phoff);
324
- plthook->phnum = ehdr->e_phnum;
325
- fd = open(filename, O_RDONLY, 0);
326
- if (fd == -1) {
327
- set_errmsg("Could not open %s: %s", filename, strerror(errno));
328
- rv = PLTHOOK_FILE_NOT_FOUND;
329
- goto error_exit;
330
- }
331
- shdr_size = ehdr->e_shnum * ehdr->e_shentsize;
332
- plthook->shdr = calloc(1, shdr_size);
333
- if (plthook->shdr == NULL) {
334
- set_errmsg("failed to allocate memory: %" SIZE_T_FMT " bytes", shdr_size);
335
- rv = PLTHOOK_OUT_OF_MEMORY;
336
- goto error_exit;
337
- }
338
- offset = ehdr->e_shoff;
339
- if ((rv = lseek(fd, offset, SEEK_SET)) != offset) {
340
- set_errmsg("failed to seek to the section header table.");
341
- rv = PLTHOOK_INVALID_FILE_FORMAT;
342
- goto error_exit;
343
- }
344
- if (read(fd, plthook->shdr, shdr_size) != shdr_size) {
345
- set_errmsg("failed to read the section header table.");
346
- rv = PLTHOOK_INVALID_FILE_FORMAT;
347
- goto error_exit;
348
- }
349
- plthook->shnum = ehdr->e_shnum;
350
- plthook->shstrtab_size = plthook->shdr[ehdr->e_shstrndx].sh_size;
351
- plthook->shstrtab = malloc(plthook->shstrtab_size);
352
- if (plthook->shstrtab == NULL) {
353
- set_errmsg("failed to allocate memory: %" SIZE_T_FMT " bytes", plthook->shstrtab_size);
354
- rv = PLTHOOK_OUT_OF_MEMORY;
355
- goto error_exit;
356
- }
357
- offset = plthook->shdr[ehdr->e_shstrndx].sh_offset;
358
- if (lseek(fd, offset, SEEK_SET) != offset) {
359
- set_errmsg("failed to seek to the section header string table.");
360
- rv = PLTHOOK_INVALID_FILE_FORMAT;
361
- goto error_exit;
362
- }
363
- if (read(fd, plthook->shstrtab, plthook->shstrtab_size) != plthook->shstrtab_size) {
364
- set_errmsg("failed to read the section header string table.");
365
- rv = PLTHOOK_INVALID_FILE_FORMAT;
366
- goto error_exit;
367
- }
368
- #ifdef PT_GNU_RELRO
369
- if (page_size == 0) {
370
- page_size = sysconf(_SC_PAGESIZE);
371
- }
372
- offset = ehdr->e_phoff;
373
- if ((rv = lseek(fd, offset, SEEK_SET)) != offset) {
374
- set_errmsg("failed to seek to the program header table.");
375
- rv = PLTHOOK_INVALID_FILE_FORMAT;
376
- goto error_exit;
377
- }
378
- for (idx = 0; idx < ehdr->e_phnum; idx++) {
418
+
419
+ fseek(fp, ehdr.e_phoff, SEEK_SET);
420
+
421
+ for (idx = 0; idx < ehdr.e_phnum; idx++) {
379
422
  Elf_Phdr phdr;
380
- if (read(fd, &phdr, sizeof(phdr)) != sizeof(phdr)) {
423
+
424
+ if (fread(&phdr, sizeof(phdr), 1, fp) != 1) {
381
425
  set_errmsg("failed to read the program header table.");
382
- rv = PLTHOOK_INVALID_FILE_FORMAT;
383
- goto error_exit;
426
+ fclose(fp);
427
+ return PLTHOOK_INVALID_FILE_FORMAT;
384
428
  }
385
429
  if (phdr.p_type == PT_GNU_RELRO) {
386
- plthook->relro_start = plthook->base + phdr.p_vaddr;
430
+ plthook->relro_start = plthook->plt_addr_base + phdr.p_vaddr;
387
431
  plthook->relro_end = plthook->relro_start + phdr.p_memsz;
432
+ break;
388
433
  }
389
434
  }
435
+ fclose(fp);
436
+ return 0;
437
+ }
390
438
  #endif
391
- close(fd);
392
- fd = -1;
393
439
 
394
- rv = find_section(plthook, ".dynsym", &shdr);
440
+ static int plthook_open_real(plthook_t **plthook_out, struct link_map *lmap)
441
+ {
442
+ plthook_t plthook = {NULL,};
443
+ const Elf_Dyn *dyn;
444
+ const char *dyn_addr_base = NULL;
445
+
446
+ #if defined __linux__
447
+ plthook.plt_addr_base = (char*)lmap->l_addr;
448
+ #elif defined __FreeBSD__ || defined __sun
449
+ const Elf_Ehdr *ehdr = (const Elf_Ehdr*)lmap->l_addr;
450
+ int rv = check_elf_header(ehdr);
395
451
  if (rv != 0) {
396
- goto error_exit;
452
+ return rv;
397
453
  }
398
- if (shdr->sh_type != SHT_DYNSYM) {
399
- set_errmsg("The type of .dynsym section should be SHT_DYNSYM but %d.", shdr->sh_type);
400
- rv = PLTHOOK_INVALID_FILE_FORMAT;
401
- goto error_exit;
454
+ if (ehdr->e_type == ET_DYN) {
455
+ dyn_addr_base = (const char*)lmap->l_addr;
456
+ plthook.plt_addr_base = (const char*)lmap->l_addr;
402
457
  }
403
- if (shdr->sh_entsize != sizeof(Elf_Sym)) {
404
- set_errmsg("The size of a section header entry should be sizeof(Elf_Sym)(%" SIZE_T_FMT ") but %" SIZE_T_FMT ".",
405
- sizeof(Elf_Sym), shdr->sh_entsize);
406
- rv = PLTHOOK_INVALID_FILE_FORMAT;
407
- goto error_exit;
458
+ #else
459
+ #error unsupported OS
460
+ #endif
461
+
462
+ /* get .dynsym section */
463
+ dyn = find_dyn_by_tag(lmap->l_ld, DT_SYMTAB);
464
+ if (dyn == NULL) {
465
+ set_errmsg("failed to find DT_SYMTAB");
466
+ return PLTHOOK_INTERNAL_ERROR;
408
467
  }
409
- plthook->dynsym = (const Elf_Sym*)(plthook->base + shdr->sh_addr);
410
- plthook->dynsym_cnt = shdr->sh_size / shdr->sh_entsize;
468
+ plthook.dynsym = (const Elf_Sym*)(dyn_addr_base + dyn->d_un.d_ptr);
411
469
 
412
- rv = find_section(plthook, ".dynstr", &shdr);
413
- if (rv != 0) {
414
- goto error_exit;
470
+ /* Check sizeof(Elf_Sym) */
471
+ dyn = find_dyn_by_tag(lmap->l_ld, DT_SYMENT);
472
+ if (dyn == NULL) {
473
+ set_errmsg("failed to find DT_SYMTAB");
474
+ return PLTHOOK_INTERNAL_ERROR;
475
+ }
476
+ if (dyn->d_un.d_val != sizeof(Elf_Sym)) {
477
+ set_errmsg("DT_SYMENT size %" ELF_XWORD_FMT " != %" SIZE_T_FMT, dyn->d_un.d_val, sizeof(Elf_Sym));
478
+ return PLTHOOK_INTERNAL_ERROR;
415
479
  }
416
- if (shdr->sh_type != SHT_STRTAB) {
417
- set_errmsg("The type of .dynstrx section should be SHT_STRTAB but %d.", shdr->sh_type);
418
- rv = PLTHOOK_INVALID_FILE_FORMAT;
419
- goto error_exit;
480
+
481
+ /* get .dynstr section */
482
+ dyn = find_dyn_by_tag(lmap->l_ld, DT_STRTAB);
483
+ if (dyn == NULL) {
484
+ set_errmsg("failed to find DT_STRTAB");
485
+ return PLTHOOK_INTERNAL_ERROR;
420
486
  }
421
- plthook->dynstr = (const char*)(plthook->base + shdr->sh_addr);
422
- plthook->dynstr_size = shdr->sh_size;
487
+ plthook.dynstr = dyn_addr_base + dyn->d_un.d_ptr;
423
488
 
424
- rv = find_section(plthook, PLT_SECTION_NAME, &shdr);
425
- if (rv != 0) {
426
- goto error_exit;
489
+ /* get .dynstr size */
490
+ dyn = find_dyn_by_tag(lmap->l_ld, DT_STRSZ);
491
+ if (dyn == NULL) {
492
+ set_errmsg("failed to find DT_STRSZ");
493
+ return PLTHOOK_INTERNAL_ERROR;
494
+ }
495
+ plthook.dynstr_size = dyn->d_un.d_val;
496
+
497
+ /* get .rela.plt or .rel.plt section */
498
+ 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;
427
505
  }
428
- if (shdr->sh_entsize != sizeof(Elf_Plt_Rel)) {
429
- set_errmsg("invalid " PLT_SECTION_NAME " table entry size: %" SIZE_T_FMT, shdr->sh_entsize);
430
- rv = PLTHOOK_INVALID_FILE_FORMAT;
431
- goto error_exit;
506
+ #endif
507
+ if (dyn == NULL) {
508
+ set_errmsg("failed to find DT_JMPREL");
509
+ return PLTHOOK_INTERNAL_ERROR;
432
510
  }
433
- plthook->plt = (Elf_Plt_Rel *)(plthook->base + shdr->sh_addr);
434
- plthook->plt_cnt = shdr->sh_size / sizeof(Elf_Plt_Rel);
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 */
515
+ dyn = find_dyn_by_tag(lmap->l_ld, DT_PLTRELSZ);
516
+ if (dyn == NULL) {
517
+ set_errmsg("failed to find DT_PLTRELSZ");
518
+ return PLTHOOK_INTERNAL_ERROR;
519
+ }
435
520
 
436
- *plthook_out = plthook;
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;
526
+ size_t total_size, elem_size;
527
+
528
+ dyn = find_dyn_by_tag(lmap->l_ld, total_size_tag);
529
+ if (dyn == NULL) {
530
+ set_errmsg("failed to find 0x%x", total_size_tag);
531
+ return PLTHOOK_INTERNAL_ERROR;
532
+ }
533
+ total_size = dyn->d_un.d_ptr;
534
+
535
+ dyn = find_dyn_by_tag(lmap->l_ld, elem_size_tag);
536
+ if (dyn == NULL) {
537
+ set_errmsg("failed to find 0x%x", elem_size_tag);
538
+ return PLTHOOK_INTERNAL_ERROR;
539
+ }
540
+ elem_size = dyn->d_un.d_ptr;
541
+ plthook.plt_cnt = total_size / elem_size;
542
+ #endif
543
+ }
544
+
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
+ }
555
+ }
556
+ #endif
557
+
558
+ *plthook_out = malloc(sizeof(plthook_t));
559
+ if (*plthook_out == NULL) {
560
+ set_errmsg("failed to allocate memory: %" SIZE_T_FMT " bytes", sizeof(plthook_t));
561
+ return PLTHOOK_OUT_OF_MEMORY;
562
+ }
563
+ **plthook_out = plthook;
437
564
  return 0;
438
- error_exit:
439
- if (fd != -1) {
440
- close(fd);
565
+ }
566
+
567
+ static int check_elf_header(const Elf_Ehdr *ehdr)
568
+ {
569
+ static const unsigned short s = 1;
570
+ /* Check endianness at runtime. */
571
+ unsigned char elfdata = (*(const char*)&s) ? ELFDATA2LSB : ELFDATA2MSB;
572
+
573
+ if (ehdr == NULL) {
574
+ set_errmsg("invalid elf header address: NULL");
575
+ return PLTHOOK_INTERNAL_ERROR;
441
576
  }
442
- plthook_close(plthook);
443
- return rv;
577
+
578
+ if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG) != 0) {
579
+ set_errmsg("invalid file signature: 0x%02x,0x%02x,0x%02x,0x%02x",
580
+ ehdr->e_ident[0], ehdr->e_ident[1], ehdr->e_ident[2], ehdr->e_ident[3]);
581
+ return PLTHOOK_INVALID_FILE_FORMAT;
582
+ }
583
+ if (ehdr->e_ident[EI_CLASS] != ELF_CLASS) {
584
+ set_errmsg("invalid elf class: 0x%02x", ehdr->e_ident[EI_CLASS]);
585
+ return PLTHOOK_INVALID_FILE_FORMAT;
586
+ }
587
+ if (ehdr->e_ident[EI_DATA] != elfdata) {
588
+ set_errmsg("invalid elf data: 0x%02x", ehdr->e_ident[EI_DATA]);
589
+ return PLTHOOK_INVALID_FILE_FORMAT;
590
+ }
591
+ if (ehdr->e_ident[EI_VERSION] != EV_CURRENT) {
592
+ set_errmsg("invalid elf version: 0x%02x", ehdr->e_ident[EI_VERSION]);
593
+ return PLTHOOK_INVALID_FILE_FORMAT;
594
+ }
595
+ if (ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN) {
596
+ set_errmsg("invalid file type: 0x%04x", ehdr->e_type);
597
+ return PLTHOOK_INVALID_FILE_FORMAT;
598
+ }
599
+ if (ehdr->e_version != EV_CURRENT) {
600
+ set_errmsg("invalid object file version: %" ELF_WORD_FMT, ehdr->e_version);
601
+ return PLTHOOK_INVALID_FILE_FORMAT;
602
+ }
603
+ if (ehdr->e_ehsize != sizeof(Elf_Ehdr)) {
604
+ set_errmsg("invalid elf header size: %u", ehdr->e_ehsize);
605
+ return PLTHOOK_INVALID_FILE_FORMAT;
606
+ }
607
+ if (ehdr->e_phentsize != sizeof(Elf_Phdr)) {
608
+ set_errmsg("invalid program header table entry size: %u", ehdr->e_phentsize);
609
+ return PLTHOOK_INVALID_FILE_FORMAT;
610
+ }
611
+ return 0;
444
612
  }
445
613
 
446
614
  int plthook_enum(plthook_t *plthook, unsigned int *pos, const char **name_out, void ***addr_out)
447
615
  {
448
616
  while (*pos < plthook->plt_cnt) {
449
617
  const Elf_Plt_Rel *plt = plthook->plt + *pos;
450
- if (ELF_R_TYPE(plt->r_info) == R_JUMP_SLOT) {
618
+ if (ELF_R_TYPE(plt->r_info) == plthook->r_type) {
451
619
  size_t idx = ELF_R_SYM(plt->r_info);
452
620
 
453
- if (idx >= plthook->dynsym_cnt) {
454
- set_errmsg(".dynsym index %" SIZE_T_FMT " should be less than %" SIZE_T_FMT ".", idx, plthook->dynsym_cnt);
455
- return PLTHOOK_INVALID_FILE_FORMAT;
456
- }
457
621
  idx = plthook->dynsym[idx].st_name;
458
622
  if (idx + 1 > plthook->dynstr_size) {
459
623
  set_errmsg("too big section header string table index: %" SIZE_T_FMT, idx);
460
624
  return PLTHOOK_INVALID_FILE_FORMAT;
461
625
  }
462
626
  *name_out = plthook->dynstr + idx;
463
- *addr_out = (void**)(plthook->base + plt->r_offset);
627
+ *addr_out = (void**)(plthook->plt_addr_base + plt->r_offset);
464
628
  (*pos)++;
465
629
  return 0;
466
630
  }
@@ -486,7 +650,7 @@ int plthook_replace(plthook_t *plthook, const char *funcname, void *funcaddr, vo
486
650
  while ((rv = plthook_enum(plthook, &pos, &name, &addr)) == 0) {
487
651
  if (strncmp(name, funcname, funcnamelen) == 0) {
488
652
  if (name[funcnamelen] == '\0' || name[funcnamelen] == '@') {
489
- #ifdef PT_GNU_RELRO
653
+ #ifdef SUPPORT_RELRO
490
654
  void *maddr = NULL;
491
655
  if (plthook->relro_start <= (char*)addr && (char*)addr < plthook->relro_end) {
492
656
  maddr = (void*)((size_t)addr & ~(page_size - 1));
@@ -501,7 +665,7 @@ int plthook_replace(plthook_t *plthook, const char *funcname, void *funcaddr, vo
501
665
  *oldfunc = *addr;
502
666
  }
503
667
  *addr = funcaddr;
504
- #ifdef PT_GNU_RELRO
668
+ #ifdef SUPPORT_RELRO
505
669
  if (maddr != NULL) {
506
670
  mprotect(maddr, page_size, PROT_READ);
507
671
  }
@@ -520,8 +684,6 @@ int plthook_replace(plthook_t *plthook, const char *funcname, void *funcaddr, vo
520
684
  void plthook_close(plthook_t *plthook)
521
685
  {
522
686
  if (plthook != NULL) {
523
- free(plthook->shdr);
524
- free(plthook->shstrtab);
525
687
  free(plthook);
526
688
  }
527
689
  }
@@ -531,84 +693,6 @@ const char *plthook_error(void)
531
693
  return errmsg;
532
694
  }
533
695
 
534
- static int check_elf_header(const Elf_Ehdr *ehdr)
535
- {
536
- if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG) != 0) {
537
- set_errmsg("invalid file signature: 0x%02x,0x%02x,0x%02x,0x%02x",
538
- ehdr->e_ident[0], ehdr->e_ident[1], ehdr->e_ident[2], ehdr->e_ident[3]);
539
- return PLTHOOK_INVALID_FILE_FORMAT;
540
- }
541
- if (ehdr->e_ident[EI_CLASS] != ELF_CLASS) {
542
- set_errmsg("invalid elf class: 0x%02x", ehdr->e_ident[EI_CLASS]);
543
- return PLTHOOK_INVALID_FILE_FORMAT;
544
- }
545
- if (ehdr->e_ident[EI_DATA] != ELF_DATA) {
546
- set_errmsg("invalid elf data: 0x%02x", ehdr->e_ident[EI_DATA]);
547
- return PLTHOOK_INVALID_FILE_FORMAT;
548
- }
549
- if (ehdr->e_ident[EI_VERSION] != EV_CURRENT) {
550
- set_errmsg("invalid elf version: 0x%02x", ehdr->e_ident[EI_VERSION]);
551
- return PLTHOOK_INVALID_FILE_FORMAT;
552
- }
553
- if (ehdr->e_ident[EI_OSABI] != ELF_OSABI) {
554
- #ifdef ELF_OSABI_ALT
555
- if (ehdr->e_ident[EI_OSABI] != ELF_OSABI_ALT) {
556
- set_errmsg("invalid OS ABI: 0x%02x", ehdr->e_ident[EI_OSABI]);
557
- return PLTHOOK_INVALID_FILE_FORMAT;
558
- }
559
- #else
560
- set_errmsg("invalid OS ABI: 0x%02x", ehdr->e_ident[EI_OSABI]);
561
- return PLTHOOK_INVALID_FILE_FORMAT;
562
- #endif
563
- }
564
- if (ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN) {
565
- set_errmsg("invalid file type: 0x%04x", ehdr->e_type);
566
- return PLTHOOK_INVALID_FILE_FORMAT;
567
- }
568
- if (ehdr->e_machine != E_MACHINE) {
569
- set_errmsg("invalid machine type: %u", ehdr->e_machine);
570
- return PLTHOOK_INVALID_FILE_FORMAT;
571
- }
572
- if (ehdr->e_version != EV_CURRENT) {
573
- set_errmsg("invalid object file version: %u", ehdr->e_version);
574
- return PLTHOOK_INVALID_FILE_FORMAT;
575
- }
576
- if (ehdr->e_ehsize != sizeof(Elf_Ehdr)) {
577
- set_errmsg("invalid elf header size: %u", ehdr->e_ehsize);
578
- return PLTHOOK_INVALID_FILE_FORMAT;
579
- }
580
- if (ehdr->e_phentsize != sizeof(Elf_Phdr)) {
581
- set_errmsg("invalid program header table entry size: %u", ehdr->e_phentsize);
582
- return PLTHOOK_INVALID_FILE_FORMAT;
583
- }
584
- if (ehdr->e_shentsize != sizeof(Elf_Shdr)) {
585
- set_errmsg("invalid section header table entry size: %u", ehdr->e_shentsize);
586
- return PLTHOOK_INVALID_FILE_FORMAT;
587
- }
588
- return 0;
589
- }
590
-
591
- static int find_section(plthook_t *image, const char *name, const Elf_Shdr **out)
592
- {
593
- const Elf_Shdr *shdr = image->shdr;
594
- const Elf_Shdr *shdr_end = shdr + image->shnum;
595
- size_t namelen = strlen(name);
596
-
597
- while (shdr < shdr_end) {
598
- if (shdr->sh_name + namelen >= image->shstrtab_size) {
599
- set_errmsg("too big section header string table index: %u", shdr->sh_name);
600
- return PLTHOOK_INVALID_FILE_FORMAT;
601
- }
602
- if (strcmp(image->shstrtab + shdr->sh_name, name) == 0) {
603
- *out = shdr;
604
- return 0;
605
- }
606
- shdr++;
607
- }
608
- set_errmsg("failed to find the section header: %s", name);
609
- return PLTHOOK_INVALID_FILE_FORMAT;
610
- }
611
-
612
696
  static void set_errmsg(const char *fmt, ...)
613
697
  {
614
698
  va_list ap;