ruby-oci8 2.2.4.1 → 2.2.5
Sign up to get free protection for your applications and to get access to all the features.
- data/ChangeLog +51 -1
- data/NEWS +58 -0
- data/README.md +4 -1
- data/dist-files +6 -2
- data/docs/bind-array-to-in_cond.md +1 -1
- data/docs/ldap-auth-and-function-interposition.md +123 -0
- data/docs/number-type-mapping.md +79 -0
- data/ext/oci8/apiwrap.yml +0 -22
- data/ext/oci8/error.c +18 -33
- data/ext/oci8/oci8.c +0 -99
- data/ext/oci8/oci8lib.c +38 -30
- data/ext/oci8/ocinumber.c +11 -7
- data/ext/oci8/plthook_elf.c +384 -300
- data/lib/oci8/bindtype.rb +1 -1
- data/lib/oci8/check_load_error.rb +16 -4
- data/lib/oci8/cursor.rb +2 -4
- data/lib/oci8/oci8.rb +19 -24
- data/lib/oci8/version.rb +1 -1
- data/test/setup_test_package.sql +59 -0
- data/test/test_bind_boolean.rb +99 -0
- data/test/test_oranumber.rb +3 -3
- metadata +9 -6
data/ext/oci8/oci8.c
CHANGED
@@ -424,49 +424,6 @@ static VALUE oci8_parse_connect_string(VALUE self, VALUE conn_str)
|
|
424
424
|
return rb_ary_new3(4, user, pass, dbname, mode);
|
425
425
|
}
|
426
426
|
|
427
|
-
/*
|
428
|
-
* Logoff strategy for sessions connected by OCILogon.
|
429
|
-
*/
|
430
|
-
typedef struct {
|
431
|
-
OCISvcCtx *svchp;
|
432
|
-
OCISession *usrhp;
|
433
|
-
OCIServer *srvhp;
|
434
|
-
} simple_logoff_arg_t;
|
435
|
-
|
436
|
-
static void *simple_logoff_prepare(oci8_svcctx_t *svcctx)
|
437
|
-
{
|
438
|
-
simple_logoff_arg_t *sla = xmalloc(sizeof(simple_logoff_arg_t));
|
439
|
-
sla->svchp = svcctx->base.hp.svc;
|
440
|
-
sla->usrhp = svcctx->usrhp;
|
441
|
-
sla->srvhp = svcctx->srvhp;
|
442
|
-
svcctx->usrhp = NULL;
|
443
|
-
svcctx->srvhp = NULL;
|
444
|
-
return sla;
|
445
|
-
}
|
446
|
-
|
447
|
-
static void *simple_logoff_execute(void *arg)
|
448
|
-
{
|
449
|
-
simple_logoff_arg_t *sla = (simple_logoff_arg_t *)arg;
|
450
|
-
OCIError *errhp = oci8_errhp;
|
451
|
-
boolean txn = TRUE;
|
452
|
-
sword rv;
|
453
|
-
|
454
|
-
if (oracle_client_version >= ORAVER_12_1) {
|
455
|
-
OCIAttrGet(sla->usrhp, OCI_HTYPE_SESSION, &txn, NULL, OCI_ATTR_TRANSACTION_IN_PROGRESS, errhp);
|
456
|
-
}
|
457
|
-
if (txn) {
|
458
|
-
OCITransRollback(sla->svchp, errhp, OCI_DEFAULT);
|
459
|
-
}
|
460
|
-
rv = OCILogoff(sla->svchp, errhp);
|
461
|
-
xfree(sla);
|
462
|
-
return (void*)(VALUE)rv;
|
463
|
-
}
|
464
|
-
|
465
|
-
static const oci8_logoff_strategy_t simple_logoff = {
|
466
|
-
simple_logoff_prepare,
|
467
|
-
simple_logoff_execute,
|
468
|
-
};
|
469
|
-
|
470
427
|
/*
|
471
428
|
* Logoff strategy for sessions connected by OCIServerAttach and OCISessionBegin.
|
472
429
|
*/
|
@@ -531,61 +488,6 @@ static const oci8_logoff_strategy_t complex_logoff = {
|
|
531
488
|
complex_logoff_execute,
|
532
489
|
};
|
533
490
|
|
534
|
-
/*
|
535
|
-
* @overload logon2(username, password, dbname, mode)
|
536
|
-
*
|
537
|
-
* Creates a simple logon session by the OCI function OCILogon2().
|
538
|
-
*
|
539
|
-
* @param [String] username
|
540
|
-
* @param [String] password
|
541
|
-
* @param [String] dbname
|
542
|
-
* @param [Integer] mode
|
543
|
-
* @private
|
544
|
-
*/
|
545
|
-
static VALUE oci8_logon2(VALUE self, VALUE username, VALUE password, VALUE dbname, VALUE mode)
|
546
|
-
{
|
547
|
-
oci8_svcctx_t *svcctx = oci8_get_svcctx(self);
|
548
|
-
ub4 logon2_mode;
|
549
|
-
|
550
|
-
if (svcctx->logoff_strategy != NULL) {
|
551
|
-
rb_raise(rb_eRuntimeError, "Could not reuse the session.");
|
552
|
-
}
|
553
|
-
|
554
|
-
/* check arugmnets */
|
555
|
-
OCI8SafeStringValue(username);
|
556
|
-
OCI8SafeStringValue(password);
|
557
|
-
if (!NIL_P(dbname)) {
|
558
|
-
OCI8SafeStringValue(dbname);
|
559
|
-
}
|
560
|
-
logon2_mode = NUM2UINT(mode);
|
561
|
-
|
562
|
-
/* logon */
|
563
|
-
svcctx->base.type = OCI_HTYPE_SVCCTX;
|
564
|
-
chker2(OCILogon2_nb(svcctx, oci8_envhp, oci8_errhp, &svcctx->base.hp.svc,
|
565
|
-
RSTRING_ORATEXT(username), RSTRING_LEN(username),
|
566
|
-
RSTRING_ORATEXT(password), RSTRING_LEN(password),
|
567
|
-
NIL_P(dbname) ? NULL : RSTRING_ORATEXT(dbname),
|
568
|
-
NIL_P(dbname) ? 0 : RSTRING_LEN(dbname), logon2_mode),
|
569
|
-
&svcctx->base);
|
570
|
-
svcctx->logoff_strategy = &simple_logoff;
|
571
|
-
|
572
|
-
if (logon2_mode & OCI_LOGON2_CPOOL) {
|
573
|
-
svcctx->state |= OCI8_STATE_CPOOL;
|
574
|
-
}
|
575
|
-
|
576
|
-
/* setup the session handle */
|
577
|
-
chker2(OCIAttrGet(svcctx->base.hp.ptr, OCI_HTYPE_SVCCTX, &svcctx->usrhp, 0, OCI_ATTR_SESSION, oci8_errhp),
|
578
|
-
&svcctx->base);
|
579
|
-
copy_session_handle(svcctx);
|
580
|
-
|
581
|
-
/* setup the server handle */
|
582
|
-
chker2(OCIAttrGet(svcctx->base.hp.ptr, OCI_HTYPE_SVCCTX, &svcctx->srvhp, 0, OCI_ATTR_SERVER, oci8_errhp),
|
583
|
-
&svcctx->base);
|
584
|
-
copy_server_handle(svcctx);
|
585
|
-
|
586
|
-
return Qnil;
|
587
|
-
}
|
588
|
-
|
589
491
|
/*
|
590
492
|
* @overload allocate_handles()
|
591
493
|
*
|
@@ -1107,7 +1009,6 @@ void Init_oci8(VALUE *out)
|
|
1107
1009
|
rb_define_singleton_method_nodoc(cOCI8, "__set_prop", oci8_s_set_prop, 2);
|
1108
1010
|
rb_define_singleton_method(cOCI8, "error_message", oci8_s_error_message, 1);
|
1109
1011
|
rb_define_private_method(cOCI8, "parse_connect_string", oci8_parse_connect_string, 1);
|
1110
|
-
rb_define_private_method(cOCI8, "logon2", oci8_logon2, 4);
|
1111
1012
|
rb_define_private_method(cOCI8, "allocate_handles", oci8_allocate_handles, 0);
|
1112
1013
|
rb_define_private_method(cOCI8, "server_attach", oci8_server_attach, 2);
|
1113
1014
|
rb_define_private_method(cOCI8, "session_begin", oci8_session_begin, 2);
|
data/ext/oci8/oci8lib.c
CHANGED
@@ -558,6 +558,24 @@ static VALUE ensure_func(cb_arg_t *arg)
|
|
558
558
|
|
559
559
|
#ifndef _WIN32
|
560
560
|
#include <dlfcn.h>
|
561
|
+
static void *load_file(const char *filename, int flags, VALUE errors)
|
562
|
+
{
|
563
|
+
void *handle = dlopen(filename, flags);
|
564
|
+
|
565
|
+
if (handle == NULL) {
|
566
|
+
char *err = dlerror();
|
567
|
+
VALUE msg;
|
568
|
+
|
569
|
+
if (strstr(err, filename) == NULL) {
|
570
|
+
msg = rb_sprintf("%s: %s", filename, err);
|
571
|
+
msg = rb_enc_associate_index(msg, rb_locale_encindex());
|
572
|
+
} else {
|
573
|
+
msg = rb_locale_str_new_cstr(err);
|
574
|
+
}
|
575
|
+
rb_ary_push(errors, msg);
|
576
|
+
}
|
577
|
+
return handle;
|
578
|
+
}
|
561
579
|
#endif
|
562
580
|
|
563
581
|
void *oci8_find_symbol(const char *symbol_name)
|
@@ -600,8 +618,6 @@ void *oci8_find_symbol(const char *symbol_name)
|
|
600
618
|
"libclntsh.sl.12.1",
|
601
619
|
"libclntsh.sl.11.1",
|
602
620
|
"libclntsh.sl.10.1",
|
603
|
-
"libclntsh.sl.9.0",
|
604
|
-
"libclntsh.sl.8.0",
|
605
621
|
#elif defined(__APPLE__)
|
606
622
|
/* Mac OS X */
|
607
623
|
"libclntsh.dylib.12.1",
|
@@ -612,46 +628,38 @@ void *oci8_find_symbol(const char *symbol_name)
|
|
612
628
|
"libclntsh.so.12.1",
|
613
629
|
"libclntsh.so.11.1",
|
614
630
|
"libclntsh.so.10.1",
|
615
|
-
"libclntsh.so.9.0",
|
616
|
-
"libclntsh.so.8.0",
|
617
631
|
#endif
|
618
632
|
};
|
619
633
|
#define NUM_SONAMES (sizeof(sonames)/sizeof(sonames[0]))
|
634
|
+
#if defined(_AIX) /* AIX */
|
635
|
+
#define BASE_SONAME "libclntsh.a(shr.o)"
|
636
|
+
#elif defined(__hppa) /* HP-UX(PA-RISC) */
|
637
|
+
#define BASE_SONAME "libclntsh.sl"
|
638
|
+
#elif !defined(__CYGWIN__) && !defined(__APPLE__)
|
639
|
+
#define BASE_SONAME "libclntsh.so"
|
640
|
+
#endif
|
620
641
|
size_t idx;
|
621
|
-
|
642
|
+
VALUE err = rb_ary_new();
|
622
643
|
|
623
644
|
#ifdef _AIX
|
624
645
|
#define DLOPEN_FLAG (RTLD_LAZY|RTLD_GLOBAL|RTLD_MEMBER)
|
625
646
|
#else
|
626
647
|
#define DLOPEN_FLAG (RTLD_LAZY|RTLD_GLOBAL)
|
627
648
|
#endif
|
628
|
-
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
|
649
|
+
#ifdef BASE_SONAME
|
650
|
+
char *oracle_home = getenv("ORACLE_HOME");
|
651
|
+
|
652
|
+
if (oracle_home != NULL) {
|
653
|
+
VALUE fname = rb_str_buf_cat2(rb_str_buf_new_cstr(oracle_home), "/lib/" BASE_SONAME);
|
654
|
+
handle = load_file(StringValueCStr(fname), DLOPEN_FLAG, err);
|
655
|
+
RB_GC_GUARD(fname);
|
656
|
+
}
|
657
|
+
#endif
|
658
|
+
for (idx = 0; handle == NULL && idx < NUM_SONAMES; idx++) {
|
659
|
+
handle = load_file(sonames[idx], DLOPEN_FLAG, err);
|
634
660
|
}
|
635
661
|
if (handle == NULL) {
|
636
|
-
VALUE msg;
|
637
|
-
const VALUE *arr = RARRAY_CONST_PTR(err);
|
638
|
-
|
639
|
-
msg = rb_str_buf_new(NUM_SONAMES * 50);
|
640
|
-
for (idx = 0; idx < NUM_SONAMES; idx++) {
|
641
|
-
const char *errmsg = RSTRING_PTR(arr[idx]);
|
642
|
-
if (idx != 0) {
|
643
|
-
rb_str_buf_cat2(msg, " ");
|
644
|
-
}
|
645
|
-
if (strstr(errmsg, sonames[idx]) == NULL) {
|
646
|
-
/* prepend "soname: " if soname is not found in
|
647
|
-
* the error message.
|
648
|
-
*/
|
649
|
-
rb_str_buf_cat2(msg, sonames[idx]);
|
650
|
-
rb_str_buf_cat2(msg, ": ");
|
651
|
-
}
|
652
|
-
rb_str_buf_append(msg, arr[idx]);
|
653
|
-
rb_str_buf_cat2(msg, ";");
|
654
|
-
}
|
662
|
+
VALUE msg = rb_ary_join(err, rb_usascii_str_new_cstr("; "));
|
655
663
|
rb_exc_raise(rb_exc_new3(rb_eLoadError, msg));
|
656
664
|
}
|
657
665
|
}
|
data/ext/oci8/ocinumber.c
CHANGED
@@ -1441,17 +1441,17 @@ static VALUE onum_to_d_real(OCINumber *num, OCIError *errhp)
|
|
1441
1441
|
}
|
1442
1442
|
|
1443
1443
|
/*
|
1444
|
-
* @overload
|
1444
|
+
* @overload has_fractional_part?
|
1445
1445
|
*
|
1446
|
-
* Returns <code>true</code> if <i>self</i> has a
|
1446
|
+
* Returns <code>true</code> if <i>self</i> has a fractional part.
|
1447
1447
|
*
|
1448
1448
|
* @example
|
1449
|
-
* OraNumber(10).
|
1450
|
-
* OraNumber(10.1).
|
1449
|
+
* OraNumber(10).has_fractional_part? # => false
|
1450
|
+
* OraNumber(10.1).has_fractional_part? # => true
|
1451
1451
|
*
|
1452
|
-
* @since 2.
|
1452
|
+
* @since 2.2.5
|
1453
1453
|
*/
|
1454
|
-
static VALUE
|
1454
|
+
static VALUE onum_has_fractional_part_p(VALUE self)
|
1455
1455
|
{
|
1456
1456
|
OCIError *errhp = oci8_errhp;
|
1457
1457
|
boolean result;
|
@@ -1873,7 +1873,7 @@ Init_oci_number(VALUE cOCI8, OCIError *errhp)
|
|
1873
1873
|
rb_define_method(cOCINumber, "to_f", onum_to_f, 0);
|
1874
1874
|
rb_define_method(cOCINumber, "to_r", onum_to_r, 0);
|
1875
1875
|
rb_define_method(cOCINumber, "to_d", onum_to_d, 0);
|
1876
|
-
rb_define_method(cOCINumber, "
|
1876
|
+
rb_define_method(cOCINumber, "has_fractional_part?", onum_has_fractional_part_p, 0);
|
1877
1877
|
rb_define_method(cOCINumber, "to_onum", onum_to_onum, 0);
|
1878
1878
|
|
1879
1879
|
rb_define_method(cOCINumber, "zero?", onum_zero_p, 0);
|
@@ -1902,6 +1902,10 @@ Init_oci_number(VALUE cOCI8, OCIError *errhp)
|
|
1902
1902
|
dummy2 = rb_define_class_under(mOCI8BindType, "Integer", cOCI8BindTypeBase);
|
1903
1903
|
dummy3 = rb_define_class_under(mOCI8BindType, "Float", cOCI8BindTypeBase);
|
1904
1904
|
#endif
|
1905
|
+
|
1906
|
+
/* The following method definition is for backward-compatibility.
|
1907
|
+
I misunderstood the name of numbers after a decimal point. */
|
1908
|
+
rb_define_method_nodoc(cOCINumber, "has_decimal_part?", onum_has_fractional_part_p, 0);
|
1905
1909
|
}
|
1906
1910
|
|
1907
1911
|
/*
|
data/ext/oci8/plthook_elf.c
CHANGED
@@ -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 <
|
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
|
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
|
-
|
75
|
-
#
|
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
|
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
|
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
|
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
|
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
|
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
|
-
|
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
|
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
|
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
|
-
|
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 (
|
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,
|
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
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
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
|
256
|
+
set_errmsg("Could not open %s: %s", auxv_file,
|
223
257
|
strerror(errno));
|
224
258
|
return PLTHOOK_INTERNAL_ERROR;
|
225
259
|
}
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
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 (
|
234
|
-
set_errmsg("
|
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,
|
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,
|
295
|
+
return plthook_open_real(plthook_out, lmap);
|
284
296
|
}
|
285
297
|
|
286
|
-
static
|
298
|
+
static const Elf_Dyn *find_dyn_by_tag(const Elf_Dyn *dyn, Elf_Sxword tag)
|
287
299
|
{
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
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
|
-
|
305
|
-
|
306
|
-
|
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
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
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
|
-
|
316
|
-
|
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
|
-
|
415
|
+
fclose(fp);
|
416
|
+
return rv;
|
319
417
|
}
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
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
|
-
|
423
|
+
|
424
|
+
if (fread(&phdr, sizeof(phdr), 1, fp) != 1) {
|
381
425
|
set_errmsg("failed to read the program header table.");
|
382
|
-
|
383
|
-
|
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->
|
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
|
-
|
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
|
-
|
452
|
+
return rv;
|
397
453
|
}
|
398
|
-
if (
|
399
|
-
|
400
|
-
|
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
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
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
|
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
|
-
|
413
|
-
|
414
|
-
|
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
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
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
|
422
|
-
plthook->dynstr_size = shdr->sh_size;
|
487
|
+
plthook.dynstr = dyn_addr_base + dyn->d_un.d_ptr;
|
423
488
|
|
424
|
-
|
425
|
-
|
426
|
-
|
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
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
506
|
+
#endif
|
507
|
+
if (dyn == NULL) {
|
508
|
+
set_errmsg("failed to find DT_JMPREL");
|
509
|
+
return PLTHOOK_INTERNAL_ERROR;
|
432
510
|
}
|
433
|
-
plthook
|
434
|
-
|
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
|
-
|
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
|
-
|
439
|
-
|
440
|
-
|
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
|
-
|
443
|
-
|
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) ==
|
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->
|
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
|
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
|
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;
|