ruby-oci8 2.2.4.1 → 2.2.5
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.
- 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;
|