ruby-oci8 2.2.3 → 2.2.12

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 (77) hide show
  1. checksums.yaml +7 -0
  2. data/ChangeLog +427 -0
  3. data/NEWS +335 -42
  4. data/README.md +20 -9
  5. data/dist-files +9 -3
  6. data/docs/bind-array-to-in_cond.md +2 -2
  7. data/docs/conflicts-local-connections-and-processes.md +7 -4
  8. data/docs/hanging-after-inactivity.md +63 -0
  9. data/docs/install-binary-package.md +15 -11
  10. data/docs/install-full-client.md +18 -21
  11. data/docs/install-instant-client.md +45 -27
  12. data/docs/install-on-osx.md +31 -120
  13. data/docs/ldap-auth-and-function-interposition.md +123 -0
  14. data/docs/number-type-mapping.md +79 -0
  15. data/docs/platform-specific-issues.md +17 -50
  16. data/docs/report-installation-issue.md +3 -0
  17. data/docs/timeout-parameters.md +3 -0
  18. data/ext/oci8/apiwrap.c.tmpl +2 -5
  19. data/ext/oci8/apiwrap.rb +6 -1
  20. data/ext/oci8/apiwrap.yml +34 -22
  21. data/ext/oci8/attr.c +4 -2
  22. data/ext/oci8/bind.c +366 -6
  23. data/ext/oci8/connection_pool.c +3 -3
  24. data/ext/oci8/encoding.c +5 -5
  25. data/ext/oci8/env.c +8 -2
  26. data/ext/oci8/error.c +24 -16
  27. data/ext/oci8/extconf.rb +8 -4
  28. data/ext/oci8/hook_funcs.c +274 -61
  29. data/ext/oci8/lob.c +31 -75
  30. data/ext/oci8/metadata.c +2 -2
  31. data/ext/oci8/object.c +72 -27
  32. data/ext/oci8/oci8.c +45 -132
  33. data/ext/oci8/oci8.h +32 -88
  34. data/ext/oci8/oci8lib.c +178 -38
  35. data/ext/oci8/ocihandle.c +37 -37
  36. data/ext/oci8/ocinumber.c +23 -18
  37. data/ext/oci8/oraconf.rb +158 -339
  38. data/ext/oci8/oradate.c +19 -19
  39. data/ext/oci8/plthook.h +10 -0
  40. data/ext/oci8/plthook_elf.c +433 -268
  41. data/ext/oci8/plthook_osx.c +40 -9
  42. data/ext/oci8/plthook_win32.c +9 -0
  43. data/ext/oci8/stmt.c +52 -17
  44. data/ext/oci8/win32.c +4 -22
  45. data/lib/oci8/bindtype.rb +1 -15
  46. data/lib/oci8/check_load_error.rb +57 -10
  47. data/lib/oci8/cursor.rb +57 -25
  48. data/lib/oci8/metadata.rb +9 -1
  49. data/lib/oci8/object.rb +10 -0
  50. data/lib/oci8/oci8.rb +33 -28
  51. data/lib/oci8/oracle_version.rb +11 -1
  52. data/lib/oci8/properties.rb +22 -0
  53. data/lib/oci8/version.rb +1 -1
  54. data/lib/oci8.rb +48 -4
  55. data/lib/ruby-oci8.rb +0 -3
  56. data/pre-distclean.rb +1 -3
  57. data/ruby-oci8.gemspec +3 -8
  58. data/setup.rb +11 -2
  59. data/test/README.md +37 -0
  60. data/test/config.rb +1 -1
  61. data/test/setup_test_object.sql +21 -13
  62. data/test/setup_test_package.sql +59 -0
  63. data/test/test_all.rb +2 -0
  64. data/test/test_bind_boolean.rb +99 -0
  65. data/test/test_bind_integer.rb +47 -0
  66. data/test/test_break.rb +11 -9
  67. data/test/test_clob.rb +4 -16
  68. data/test/test_connstr.rb +29 -13
  69. data/test/test_datetime.rb +8 -3
  70. data/test/test_object.rb +27 -9
  71. data/test/test_oci8.rb +170 -46
  72. data/test/test_oranumber.rb +12 -6
  73. data/test/test_package_type.rb +15 -3
  74. data/test/test_properties.rb +17 -0
  75. metadata +40 -54
  76. data/docs/osx-install-dev-tools.png +0 -0
  77. 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;