ruby-oci8 2.2.0.2 → 2.2.12

Sign up to get free protection for your applications and to get access to all the features.
Files changed (83) hide show
  1. checksums.yaml +7 -0
  2. data/.yardopts +1 -6
  3. data/ChangeLog +600 -0
  4. data/NEWS +426 -35
  5. data/README.md +27 -9
  6. data/dist-files +13 -2
  7. data/docs/bind-array-to-in_cond.md +38 -0
  8. data/docs/conflicts-local-connections-and-processes.md +98 -0
  9. data/docs/hanging-after-inactivity.md +63 -0
  10. data/docs/install-binary-package.md +15 -11
  11. data/docs/install-full-client.md +18 -21
  12. data/docs/install-instant-client.md +45 -27
  13. data/docs/install-on-osx.md +31 -117
  14. data/docs/ldap-auth-and-function-interposition.md +123 -0
  15. data/docs/number-type-mapping.md +79 -0
  16. data/docs/platform-specific-issues.md +17 -50
  17. data/docs/report-installation-issue.md +11 -8
  18. data/docs/timeout-parameters.md +94 -0
  19. data/ext/oci8/apiwrap.c.tmpl +2 -5
  20. data/ext/oci8/apiwrap.rb +6 -1
  21. data/ext/oci8/apiwrap.yml +39 -143
  22. data/ext/oci8/attr.c +4 -2
  23. data/ext/oci8/bind.c +421 -9
  24. data/ext/oci8/connection_pool.c +3 -3
  25. data/ext/oci8/encoding.c +5 -5
  26. data/ext/oci8/env.c +8 -2
  27. data/ext/oci8/error.c +24 -16
  28. data/ext/oci8/extconf.rb +35 -63
  29. data/ext/oci8/hook_funcs.c +274 -61
  30. data/ext/oci8/lob.c +31 -75
  31. data/ext/oci8/metadata.c +8 -6
  32. data/ext/oci8/object.c +119 -29
  33. data/ext/oci8/oci8.c +46 -133
  34. data/ext/oci8/oci8.h +40 -123
  35. data/ext/oci8/oci8lib.c +178 -46
  36. data/ext/oci8/ocihandle.c +37 -37
  37. data/ext/oci8/ocinumber.c +24 -35
  38. data/ext/oci8/oraconf.rb +168 -337
  39. data/ext/oci8/oradate.c +19 -19
  40. data/ext/oci8/plthook.h +10 -0
  41. data/ext/oci8/plthook_elf.c +433 -268
  42. data/ext/oci8/plthook_osx.c +40 -9
  43. data/ext/oci8/plthook_win32.c +16 -1
  44. data/ext/oci8/stmt.c +52 -17
  45. data/ext/oci8/win32.c +4 -22
  46. data/lib/oci8/bindtype.rb +10 -17
  47. data/lib/oci8/check_load_error.rb +57 -10
  48. data/lib/oci8/compat.rb +5 -1
  49. data/lib/oci8/connection_pool.rb +74 -3
  50. data/lib/oci8/cursor.rb +70 -31
  51. data/lib/oci8/metadata.rb +9 -1
  52. data/lib/oci8/object.rb +14 -1
  53. data/lib/oci8/oci8.rb +184 -58
  54. data/lib/oci8/ocihandle.rb +0 -16
  55. data/lib/oci8/oracle_version.rb +11 -1
  56. data/lib/oci8/properties.rb +55 -0
  57. data/lib/oci8/version.rb +1 -1
  58. data/lib/oci8.rb +48 -4
  59. data/lib/ruby-oci8.rb +1 -0
  60. data/pre-distclean.rb +1 -3
  61. data/ruby-oci8.gemspec +4 -9
  62. data/setup.rb +11 -2
  63. data/test/README.md +37 -0
  64. data/test/config.rb +8 -1
  65. data/test/setup_test_object.sql +42 -14
  66. data/test/setup_test_package.sql +59 -0
  67. data/test/test_all.rb +4 -0
  68. data/test/test_bind_array.rb +70 -0
  69. data/test/test_bind_boolean.rb +99 -0
  70. data/test/test_bind_integer.rb +47 -0
  71. data/test/test_break.rb +11 -9
  72. data/test/test_clob.rb +5 -17
  73. data/test/test_connstr.rb +142 -0
  74. data/test/test_datetime.rb +8 -3
  75. data/test/test_metadata.rb +2 -1
  76. data/test/test_object.rb +99 -18
  77. data/test/test_oci8.rb +170 -46
  78. data/test/test_oranumber.rb +12 -6
  79. data/test/test_package_type.rb +17 -3
  80. data/test/test_properties.rb +17 -0
  81. metadata +45 -55
  82. data/docs/osx-install-dev-tools.png +0 -0
  83. data/test/README +0 -42
@@ -6,7 +6,7 @@
6
6
  *
7
7
  * ------------------------------------------------------
8
8
  *
9
- * Copyright 2013-2014 Kubo Takehiro <kubo@jiubao.org>
9
+ * Copyright 2013-2016 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:
@@ -33,22 +33,30 @@
33
33
  * or implied, of the authors.
34
34
  *
35
35
  */
36
+ #if defined(__sun) && defined(_XOPEN_SOURCE) && !defined(__EXTENSIONS__)
37
+ #define __EXTENSIONS__
38
+ #endif
39
+ #if defined(__linux__) && !defined(_GNU_SOURCE)
36
40
  #define _GNU_SOURCE
41
+ #endif
37
42
  #include <stdio.h>
38
43
  #include <stdarg.h>
39
44
  #include <stdlib.h>
40
45
  #include <unistd.h>
41
46
  #include <string.h>
42
47
  #include <limits.h>
43
- #include <sys/types.h>
44
- #include <sys/stat.h>
45
- #include <fcntl.h>
48
+ #include <sys/mman.h>
46
49
  #include <errno.h>
47
50
  #include <dlfcn.h>
48
51
  #ifdef __sun
49
- #include <procfs.h>
52
+ #include <sys/auxv.h>
50
53
  #define ELF_TARGET_ALL
51
54
  #endif /* __sun */
55
+ #ifdef __FreeBSD__
56
+ #include <sys/types.h>
57
+ #include <sys/user.h>
58
+ #include <libutil.h>
59
+ #endif
52
60
  #include <elf.h>
53
61
  #include <link.h>
54
62
  #include "plthook.h"
@@ -57,39 +65,47 @@
57
65
  #define __attribute__(arg)
58
66
  #endif
59
67
 
60
- #if defined __linux__
61
- #define ELF_OSABI ELFOSABI_SYSV
62
- #elif defined __sun
63
- #define ELF_OSABI ELFOSABI_SOLARIS
64
- #elif defined __FreeBSD__
65
- #define ELF_OSABI ELFOSABI_FREEBSD
66
- #if defined __i386__ && __ELF_WORD_SIZE == 64
68
+ #if defined __FreeBSD__ && defined __i386__ && __ELF_WORD_SIZE == 64
67
69
  #error 32-bit application on 64-bit OS is not supported.
68
70
  #endif
69
- #else
70
- #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
71
74
  #endif
72
75
 
73
76
  #if defined __x86_64__ || defined __x86_64
74
- #define ELF_DATA ELFDATA2LSB
75
- #define E_MACHINE EM_X86_64
76
- #ifdef R_X86_64_JUMP_SLOT
77
77
  #define R_JUMP_SLOT R_X86_64_JUMP_SLOT
78
- #else
79
- #define R_JUMP_SLOT R_X86_64_JMP_SLOT
80
- #endif
81
- #define SHT_PLT_REL SHT_RELA
82
78
  #define Elf_Plt_Rel Elf_Rela
83
- #define PLT_SECTION_NAME ".rela.plt"
79
+ #define PLT_DT_REL DT_RELA
80
+ #define R_GLOBAL_DATA R_X86_64_GLOB_DAT
84
81
  #elif defined __i386__ || defined __i386
85
- #define ELF_DATA ELFDATA2LSB
86
- #define E_MACHINE EM_386
87
82
  #define R_JUMP_SLOT R_386_JMP_SLOT
88
- #define SHT_PLT_REL SHT_REL
89
83
  #define Elf_Plt_Rel Elf_Rel
90
- #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
91
107
  #else
92
- #error E_MACHINE is not defined.
108
+ #error unsupported OS
93
109
  #endif
94
110
 
95
111
  #if defined __LP64__
@@ -97,12 +113,16 @@
97
113
  #define ELF_CLASS ELFCLASS64
98
114
  #endif
99
115
  #define SIZE_T_FMT "lu"
116
+ #define ELF_WORD_FMT "u"
117
+ #define ELF_XWORD_FMT "lu"
118
+ #define ELF_SXWORD_FMT "ld"
100
119
  #define Elf_Half Elf64_Half
101
- #define Elf_Addr Elf64_Addr
120
+ #define Elf_Xword Elf64_Xword
121
+ #define Elf_Sxword Elf64_Sxword
102
122
  #define Elf_Ehdr Elf64_Ehdr
103
123
  #define Elf_Phdr Elf64_Phdr
104
- #define Elf_Shdr Elf64_Shdr
105
124
  #define Elf_Sym Elf64_Sym
125
+ #define Elf_Dyn Elf64_Dyn
106
126
  #define Elf_Rel Elf64_Rel
107
127
  #define Elf_Rela Elf64_Rela
108
128
  #ifndef ELF_R_SYM
@@ -116,12 +136,22 @@
116
136
  #define ELF_CLASS ELFCLASS32
117
137
  #endif
118
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
119
148
  #define Elf_Half Elf32_Half
120
- #define Elf_Addr Elf32_Addr
149
+ #define Elf_Xword Elf32_Word
150
+ #define Elf_Sxword Elf32_Sword
121
151
  #define Elf_Ehdr Elf32_Ehdr
122
152
  #define Elf_Phdr Elf32_Phdr
123
- #define Elf_Shdr Elf32_Shdr
124
153
  #define Elf_Sym Elf32_Sym
154
+ #define Elf_Dyn Elf32_Dyn
125
155
  #define Elf_Rel Elf32_Rel
126
156
  #define Elf_Rela Elf32_Rela
127
157
  #ifndef ELF_R_SYM
@@ -132,29 +162,41 @@
132
162
  #endif
133
163
  #endif /* __LP64__ */
134
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
+
135
172
  struct plthook {
136
- const char *base;
137
- const Elf_Phdr *phdr;
138
- size_t phnum;
139
- Elf_Shdr *shdr;
140
- size_t shnum;
141
- char *shstrtab;
142
- size_t shstrtab_size;
143
173
  const Elf_Sym *dynsym;
144
- size_t dynsym_cnt;
145
174
  const char *dynstr;
146
175
  size_t dynstr_size;
176
+ const char *plt_addr_base;
147
177
  const Elf_Plt_Rel *plt;
148
178
  size_t plt_cnt;
179
+ Elf_Xword r_type;
180
+ #ifdef SUPPORT_RELRO
181
+ const char *relro_start;
182
+ const char *relro_end;
183
+ #endif
149
184
  };
150
185
 
151
186
  static char errmsg[512];
152
187
 
188
+ #ifdef SUPPORT_RELRO
189
+ static size_t page_size;
190
+ #endif
191
+
153
192
  static int plthook_open_executable(plthook_t **plthook_out);
154
193
  static int plthook_open_shared_library(plthook_t **plthook_out, const char *filename);
155
- 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);
156
199
  static int check_elf_header(const Elf_Ehdr *ehdr);
157
- static int find_section(plthook_t *image, const char *name, const Elf_Shdr **out);
158
200
  static void set_errmsg(const char *fmt, ...) __attribute__((__format__ (__printf__, 1, 2)));
159
201
 
160
202
  int plthook_open(plthook_t **plthook_out, const char *filename)
@@ -167,69 +209,71 @@ int plthook_open(plthook_t **plthook_out, const char *filename)
167
209
  }
168
210
  }
169
211
 
212
+ int plthook_open_by_handle(plthook_t **plthook_out, void *hndl)
213
+ {
214
+ struct link_map *lmap = NULL;
215
+
216
+ if (hndl == NULL) {
217
+ set_errmsg("NULL handle");
218
+ return PLTHOOK_FILE_NOT_FOUND;
219
+ }
220
+ if (dlinfo(hndl, RTLD_DI_LINKMAP, &lmap) != 0) {
221
+ set_errmsg("dlinfo error");
222
+ return PLTHOOK_FILE_NOT_FOUND;
223
+ }
224
+ return plthook_open_real(plthook_out, lmap);
225
+ }
226
+
170
227
  int plthook_open_by_address(plthook_t **plthook_out, void *address)
171
228
  {
229
+ #if defined __FreeBSD__
230
+ return PLTHOOK_NOT_IMPLEMENTED;
231
+ #else
172
232
  Dl_info info;
233
+ struct link_map *lmap = NULL;
173
234
 
174
235
  *plthook_out = NULL;
175
- if (dladdr(address, &info) == 0) {
236
+ if (dladdr1(address, &info, (void**)&lmap, RTLD_DL_LINKMAP) == 0) {
176
237
  set_errmsg("dladdr error");
177
238
  return PLTHOOK_FILE_NOT_FOUND;
178
239
  }
179
- return plthook_open_real(plthook_out, info.dli_fbase, info.dli_fname);
240
+ return plthook_open_real(plthook_out, lmap);
241
+ #endif
180
242
  }
181
243
 
182
244
  static int plthook_open_executable(plthook_t **plthook_out)
183
245
  {
184
246
  #if defined __linux__
185
- /* Open the main program. */
186
- char buf[128];
187
- FILE *fp = fopen("/proc/self/maps", "r");
188
- 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;
189
254
 
190
255
  if (fp == NULL) {
191
- set_errmsg("Could not open /proc/self/maps: %s",
256
+ set_errmsg("Could not open %s: %s", auxv_file,
192
257
  strerror(errno));
193
258
  return PLTHOOK_INTERNAL_ERROR;
194
259
  }
195
- if (fgets(buf, sizeof(buf), fp) == NULL) {
196
- set_errmsg("Could not read /proc/self/maps: %s",
197
- strerror(errno));
198
- fclose(fp);
199
- 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
+ }
200
265
  }
201
266
  fclose(fp);
202
- if (sscanf(buf, "%lx-%*x r-xp %*x %*x:%*x %*u ", &base) != 1) {
203
- set_errmsg("invalid /proc/self/maps format: %s", buf);
204
- return PLTHOOK_INTERNAL_ERROR;
205
- }
206
- return plthook_open_real(plthook_out, (const char*)base, "/proc/self/exe");
207
- #elif defined __sun
208
- prmap_t prmap;
209
- pid_t pid = getpid();
210
- char fname[128];
211
- int fd;
212
-
213
- sprintf(fname, "/proc/%d/map", pid);
214
- fd = open(fname, O_RDONLY);
215
- if (fd == -1) {
216
- set_errmsg("Could not open %s: %s", fname,
217
- strerror(errno));
267
+ if (r_debug == NULL) {
268
+ set_errmsg("Could not find r_debug");
218
269
  return PLTHOOK_INTERNAL_ERROR;
219
270
  }
220
- if (read(fd, &prmap, sizeof(prmap)) != sizeof(prmap)) {
221
- set_errmsg("Could not read %s: %s", fname,
222
- strerror(errno));
223
- close(fd);
224
- return PLTHOOK_INTERNAL_ERROR;
225
- }
226
- close(fd);
227
- sprintf(fname, "/proc/%d/object/a.out", pid);
228
- return plthook_open_real(plthook_out, (const char*)prmap.pr_vaddr, fname);
271
+ return plthook_open_real(plthook_out, r_debug->r_map);
229
272
  #elif defined __FreeBSD__
230
273
  return plthook_open_shared_library(plthook_out, NULL);
231
274
  #else
232
- #error unsupported OS
275
+ set_errmsg("Opening the main program is not supported on this platform.");
276
+ return PLTHOOK_NOT_IMPLEMENTED;
233
277
  #endif
234
278
  }
235
279
 
@@ -248,161 +292,339 @@ static int plthook_open_shared_library(plthook_t **plthook_out, const char *file
248
292
  return PLTHOOK_FILE_NOT_FOUND;
249
293
  }
250
294
  dlclose(hndl);
251
- return plthook_open_real(plthook_out, (const char*)lmap->l_addr, lmap->l_name);
295
+ return plthook_open_real(plthook_out, lmap);
252
296
  }
253
297
 
254
- 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)
255
299
  {
256
- const Elf_Ehdr *ehdr = (Elf_Ehdr *)base;
257
- const Elf_Shdr *shdr;
258
- size_t shdr_size;
259
- int fd = -1;
260
- off_t offset;
261
- plthook_t *plthook;
262
- int rv;
300
+ while (dyn->d_tag != DT_NULL) {
301
+ if (dyn->d_tag == tag) {
302
+ return dyn;
303
+ }
304
+ dyn++;
305
+ }
306
+ return NULL;
307
+ }
263
308
 
264
- if (base == NULL) {
265
- set_errmsg("The base address is zero.");
266
- 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;
267
321
  }
322
+ while (fgets(buf, PATH_MAX, fp) != NULL) {
323
+ unsigned long start, end;
324
+ int offset = 0;
268
325
 
269
- if (filename == NULL) {
270
- set_errmsg("failed to get the file name on the disk.");
271
- return PLTHOOK_FILE_NOT_FOUND;
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
+ }
272
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
273
383
 
274
- plthook = calloc(1, sizeof(plthook_t));
275
- if (plthook == NULL) {
276
- set_errmsg("failed to allocate memory: %" SIZE_T_FMT " bytes", sizeof(plthook_t));
277
- return PLTHOOK_OUT_OF_MEMORY;
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;
397
+
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);
414
+ if (rv != 0) {
415
+ fclose(fp);
416
+ return rv;
278
417
  }
279
418
 
280
- /* sanity check */
281
- rv = check_elf_header(ehdr);
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
+ }
434
+ }
435
+ fclose(fp);
436
+ return 0;
437
+ }
438
+ #endif
439
+
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);
282
451
  if (rv != 0) {
283
- goto error_exit;
452
+ return rv;
284
453
  }
285
454
  if (ehdr->e_type == ET_DYN) {
286
- plthook->base = base;
287
- }
288
- plthook->phdr = (const Elf_Phdr *)(plthook->base + ehdr->e_phoff);
289
- plthook->phnum = ehdr->e_phnum;
290
- fd = open(filename, O_RDONLY, 0);
291
- if (fd == -1) {
292
- set_errmsg("Could not open %s: %s", filename, strerror(errno));
293
- rv = PLTHOOK_FILE_NOT_FOUND;
294
- goto error_exit;
295
- }
296
- shdr_size = ehdr->e_shnum * ehdr->e_shentsize;
297
- plthook->shdr = calloc(1, shdr_size);
298
- if (plthook->shdr == NULL) {
299
- set_errmsg("failed to allocate memory: %" SIZE_T_FMT " bytes", shdr_size);
300
- rv = PLTHOOK_OUT_OF_MEMORY;
301
- goto error_exit;
302
- }
303
- offset = ehdr->e_shoff;
304
- if ((rv = lseek(fd, offset, SEEK_SET)) != offset) {
305
- set_errmsg("failed to seek to the section header table.");
306
- rv = PLTHOOK_INVALID_FILE_FORMAT;
307
- goto error_exit;
308
- }
309
- if (read(fd, plthook->shdr, shdr_size) != shdr_size) {
310
- set_errmsg("failed to read the section header table.");
311
- rv = PLTHOOK_INVALID_FILE_FORMAT;
312
- goto error_exit;
313
- }
314
- plthook->shnum = ehdr->e_shnum;
315
- plthook->shstrtab_size = plthook->shdr[ehdr->e_shstrndx].sh_size;
316
- plthook->shstrtab = malloc(plthook->shstrtab_size);
317
- if (plthook->shstrtab == NULL) {
318
- set_errmsg("failed to allocate memory: %" SIZE_T_FMT " bytes", plthook->shstrtab_size);
319
- rv = PLTHOOK_OUT_OF_MEMORY;
320
- goto error_exit;
321
- }
322
- offset = plthook->shdr[ehdr->e_shstrndx].sh_offset;
323
- if (lseek(fd, offset, SEEK_SET) != offset) {
324
- set_errmsg("failed to seek to the section header string table.");
325
- rv = PLTHOOK_INVALID_FILE_FORMAT;
326
- goto error_exit;
327
- }
328
- if (read(fd, plthook->shstrtab, plthook->shstrtab_size) != plthook->shstrtab_size) {
329
- set_errmsg("failed to read the section header string table.");
330
- rv = PLTHOOK_INVALID_FILE_FORMAT;
331
- goto error_exit;
332
- }
333
- close(fd);
334
- fd = -1;
335
-
336
- rv = find_section(plthook, ".dynsym", &shdr);
337
- if (rv != 0) {
338
- goto error_exit;
455
+ dyn_addr_base = (const char*)lmap->l_addr;
456
+ plthook.plt_addr_base = (const char*)lmap->l_addr;
457
+ }
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;
339
467
  }
340
- if (shdr->sh_type != SHT_DYNSYM) {
341
- set_errmsg("The type of .dynsym section should be SHT_DYNSYM but %d.", shdr->sh_type);
342
- rv = PLTHOOK_INVALID_FILE_FORMAT;
343
- goto error_exit;
468
+ plthook.dynsym = (const Elf_Sym*)(dyn_addr_base + dyn->d_un.d_ptr);
469
+
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;
344
475
  }
345
- if (shdr->sh_entsize != sizeof(Elf_Sym)) {
346
- set_errmsg("The size of a section header entry should be sizeof(Elf_Sym)(%" SIZE_T_FMT ") but %" SIZE_T_FMT ".",
347
- sizeof(Elf_Sym), shdr->sh_entsize);
348
- rv = PLTHOOK_INVALID_FILE_FORMAT;
349
- goto error_exit;
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;
350
479
  }
351
- plthook->dynsym = (const Elf_Sym*)(plthook->base + shdr->sh_addr);
352
- plthook->dynsym_cnt = shdr->sh_size / shdr->sh_entsize;
353
480
 
354
- rv = find_section(plthook, ".dynstr", &shdr);
355
- if (rv != 0) {
356
- goto error_exit;
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;
357
486
  }
358
- if (shdr->sh_type != SHT_STRTAB) {
359
- set_errmsg("The type of .dynstrx section should be SHT_STRTAB but %d.", shdr->sh_type);
360
- rv = PLTHOOK_INVALID_FILE_FORMAT;
361
- goto error_exit;
487
+ plthook.dynstr = dyn_addr_base + dyn->d_un.d_ptr;
488
+
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;
362
494
  }
363
- plthook->dynstr = (const char*)(plthook->base + shdr->sh_addr);
364
- plthook->dynstr_size = shdr->sh_size;
495
+ plthook.dynstr_size = dyn->d_un.d_val;
365
496
 
366
- rv = find_section(plthook, PLT_SECTION_NAME, &shdr);
367
- if (rv != 0) {
368
- goto error_exit;
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;
369
505
  }
370
- if (shdr->sh_entsize != sizeof(Elf_Plt_Rel)) {
371
- set_errmsg("invalid " PLT_SECTION_NAME " table entry size: %" SIZE_T_FMT, shdr->sh_entsize);
372
- rv = PLTHOOK_INVALID_FILE_FORMAT;
373
- goto error_exit;
506
+ #endif
507
+ if (dyn == NULL) {
508
+ set_errmsg("failed to find DT_JMPREL");
509
+ return PLTHOOK_INTERNAL_ERROR;
374
510
  }
375
- plthook->plt = (Elf_Plt_Rel *)(plthook->base + shdr->sh_addr);
376
- 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
+ }
377
520
 
378
- *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;
379
564
  return 0;
380
- error_exit:
381
- if (fd != -1) {
382
- 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;
383
576
  }
384
- plthook_close(plthook);
385
- 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;
386
612
  }
387
613
 
388
614
  int plthook_enum(plthook_t *plthook, unsigned int *pos, const char **name_out, void ***addr_out)
389
615
  {
390
616
  while (*pos < plthook->plt_cnt) {
391
617
  const Elf_Plt_Rel *plt = plthook->plt + *pos;
392
- if (ELF_R_TYPE(plt->r_info) == R_JUMP_SLOT) {
618
+ if (ELF_R_TYPE(plt->r_info) == plthook->r_type) {
393
619
  size_t idx = ELF_R_SYM(plt->r_info);
394
620
 
395
- if (idx >= plthook->dynsym_cnt) {
396
- set_errmsg(".dynsym index %" SIZE_T_FMT " should be less than %" SIZE_T_FMT ".", idx, plthook->dynsym_cnt);
397
- return PLTHOOK_INVALID_FILE_FORMAT;
398
- }
399
621
  idx = plthook->dynsym[idx].st_name;
400
622
  if (idx + 1 > plthook->dynstr_size) {
401
623
  set_errmsg("too big section header string table index: %" SIZE_T_FMT, idx);
402
624
  return PLTHOOK_INVALID_FILE_FORMAT;
403
625
  }
404
626
  *name_out = plthook->dynstr + idx;
405
- *addr_out = (void**)(plthook->base + plt->r_offset);
627
+ *addr_out = (void**)(plthook->plt_addr_base + plt->r_offset);
406
628
  (*pos)++;
407
629
  return 0;
408
630
  }
@@ -428,10 +650,26 @@ int plthook_replace(plthook_t *plthook, const char *funcname, void *funcaddr, vo
428
650
  while ((rv = plthook_enum(plthook, &pos, &name, &addr)) == 0) {
429
651
  if (strncmp(name, funcname, funcnamelen) == 0) {
430
652
  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));
660
+ return PLTHOOK_INTERNAL_ERROR;
661
+ }
662
+ }
663
+ #endif
431
664
  if (oldfunc) {
432
665
  *oldfunc = *addr;
433
666
  }
434
667
  *addr = funcaddr;
668
+ #ifdef SUPPORT_RELRO
669
+ if (maddr != NULL) {
670
+ mprotect(maddr, page_size, PROT_READ);
671
+ }
672
+ #endif
435
673
  return 0;
436
674
  }
437
675
  }
@@ -446,8 +684,6 @@ int plthook_replace(plthook_t *plthook, const char *funcname, void *funcaddr, vo
446
684
  void plthook_close(plthook_t *plthook)
447
685
  {
448
686
  if (plthook != NULL) {
449
- free(plthook->shdr);
450
- free(plthook->shstrtab);
451
687
  free(plthook);
452
688
  }
453
689
  }
@@ -457,77 +693,6 @@ const char *plthook_error(void)
457
693
  return errmsg;
458
694
  }
459
695
 
460
- static int check_elf_header(const Elf_Ehdr *ehdr)
461
- {
462
- if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG) != 0) {
463
- set_errmsg("invalid file signature: 0x%02x,0x%02x,0x%02x,0x%02x",
464
- ehdr->e_ident[0], ehdr->e_ident[1], ehdr->e_ident[2], ehdr->e_ident[3]);
465
- return PLTHOOK_INVALID_FILE_FORMAT;
466
- }
467
- if (ehdr->e_ident[EI_CLASS] != ELF_CLASS) {
468
- set_errmsg("invalid elf class: 0x%02x", ehdr->e_ident[EI_CLASS]);
469
- return PLTHOOK_INVALID_FILE_FORMAT;
470
- }
471
- if (ehdr->e_ident[EI_DATA] != ELF_DATA) {
472
- set_errmsg("invalid elf data: 0x%02x", ehdr->e_ident[EI_DATA]);
473
- return PLTHOOK_INVALID_FILE_FORMAT;
474
- }
475
- if (ehdr->e_ident[EI_VERSION] != EV_CURRENT) {
476
- set_errmsg("invalid elf version: 0x%02x", ehdr->e_ident[EI_VERSION]);
477
- return PLTHOOK_INVALID_FILE_FORMAT;
478
- }
479
- if (ehdr->e_ident[EI_OSABI] != ELF_OSABI) {
480
- set_errmsg("invalid OS ABI: 0x%02x", ehdr->e_ident[EI_OSABI]);
481
- return PLTHOOK_INVALID_FILE_FORMAT;
482
- }
483
- if (ehdr->e_type != ET_EXEC && ehdr->e_type != ET_DYN) {
484
- set_errmsg("invalid file type: 0x%04x", ehdr->e_type);
485
- return PLTHOOK_INVALID_FILE_FORMAT;
486
- }
487
- if (ehdr->e_machine != E_MACHINE) {
488
- set_errmsg("invalid machine type: %u", ehdr->e_machine);
489
- return PLTHOOK_INVALID_FILE_FORMAT;
490
- }
491
- if (ehdr->e_version != EV_CURRENT) {
492
- set_errmsg("invalid object file version: %u", ehdr->e_version);
493
- return PLTHOOK_INVALID_FILE_FORMAT;
494
- }
495
- if (ehdr->e_ehsize != sizeof(Elf_Ehdr)) {
496
- set_errmsg("invalid elf header size: %u", ehdr->e_ehsize);
497
- return PLTHOOK_INVALID_FILE_FORMAT;
498
- }
499
- if (ehdr->e_phentsize != sizeof(Elf_Phdr)) {
500
- set_errmsg("invalid program header table entry size: %u", ehdr->e_phentsize);
501
- return PLTHOOK_INVALID_FILE_FORMAT;
502
- }
503
- if (ehdr->e_shentsize != sizeof(Elf_Shdr)) {
504
- set_errmsg("invalid section header table entry size: %u", ehdr->e_shentsize);
505
- return PLTHOOK_INVALID_FILE_FORMAT;
506
- }
507
- return 0;
508
- }
509
-
510
- static int find_section(plthook_t *image, const char *name, const Elf_Shdr **out)
511
- {
512
- const Elf_Shdr *shdr = image->shdr;
513
- const Elf_Shdr *shdr_end = shdr + image->shnum;
514
- size_t namelen = strlen(name);
515
-
516
- while (shdr < shdr_end) {
517
- if (shdr->sh_name + namelen >= image->shstrtab_size) {
518
- set_errmsg("too big section header string table index: %u", shdr->sh_name);
519
- return PLTHOOK_INVALID_FILE_FORMAT;
520
- }
521
- if (strcmp(image->shstrtab + shdr->sh_name, name) == 0) {
522
- *out = shdr;
523
- return 0;
524
- }
525
- shdr++;
526
- }
527
- set_errmsg("failed to find the section header: %s", name);
528
- return PLTHOOK_INVALID_FILE_FORMAT;
529
- }
530
-
531
696
  static void set_errmsg(const char *fmt, ...)
532
697
  {
533
698
  va_list ap;