1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
|
#include <string.h>
#include "pal.h"
#include "llvm/ELF.h"
#include "tizenasanenvmodule.h"
#if __LP64__
using Addr = Elf64_Addr;
using Dyn = Elf64_Dyn;
using Sym = Elf64_Sym;
using Rel = Elf64_Rel;
using Rela = Elf64_Rela;
#else
using Addr = Elf32_Addr;
using Dyn = Elf32_Dyn;
using Sym = Elf32_Sym;
using Rel = Elf32_Rel;
using Rela = Elf32_Rela;
#endif
/*
* Request arguments for dlinfo().
*/
#define RTLD_DI_LINKMAP 2 /* Obtain link map. */
struct link_map {
Addr l_addr; /* Base Address of library */
const char *l_name; /* Absolute Path to Library */
Dyn *l_ld; /* Pointer to .dynamic in memory */
struct link_map *l_next, *l_prev; /* linked list of of mapped libs */
};
extern "C" int dlinfo(void *handle, int request, void *info);
struct plt_sym_resolver {
Sym *dynsym; // .dynsym section
char *dynstr; // .dynstr section
long reltype; // relocation type
size_t pltrel_size; // size of .rel(a).plt section
void *jmprel; // .rel(a).plt section. Exact relocation
// type is resolved at runtime
plt_sym_resolver()
: dynsym(nullptr), dynstr(nullptr), reltype(-1), pltrel_size(0),
jmprel(nullptr)
{}
bool init(void *handle)
{
struct link_map *lmap;
if (handle == nullptr || dlinfo(handle, RTLD_DI_LINKMAP, &lmap) < 0)
return false;
if (lmap == nullptr || lmap->l_ld == nullptr)
return false;
return init_relocation_info(lmap->l_ld);
}
bool is_symbol_available(const char *sym) const
{
switch (reltype) {
case DT_REL:
return is_symbol_available_in_rtable(reinterpret_cast<Rel *>(jmprel), sym);
case DT_RELA:
return is_symbol_available_in_rtable(reinterpret_cast<Rela *>(jmprel), sym);
default: // no relocations
break;
}
return false;
}
private:
bool init_relocation_info(Dyn *dynamic)
{
for (Dyn *dyn = dynamic; dyn->d_tag != DT_NULL; ++dyn) {
switch (dyn->d_tag) {
case DT_SYMTAB:
dynsym = reinterpret_cast<Sym *>(dyn->d_un.d_ptr);
break;
case DT_STRTAB:
dynstr = reinterpret_cast<char *>(dyn->d_un.d_ptr);
break;
case DT_PLTREL:
reltype = dyn->d_un.d_val;
break;
case DT_PLTRELSZ:
pltrel_size = dyn->d_un.d_val;
break;
case DT_JMPREL:
jmprel = reinterpret_cast<void *>(dyn->d_un.d_ptr);
break;
default:
break;
}
}
if (dynsym == nullptr ||
dynstr == nullptr ||
jmprel == nullptr ||
pltrel_size == 0 ||
(reltype != DT_REL && reltype != DT_RELA))
return false;
return true;
}
template<typename Rel>
bool is_symbol_available_in_rtable(const Rel *rel_table, const char *sym) const
{
if (rel_table == nullptr || pltrel_size == 0)
return false;
const size_t rel_cnt = pltrel_size / sizeof(Rel);
const Rel *rel_end = rel_table + rel_cnt;
for (const Rel *rel = rel_table; rel < rel_end; ++rel) {
if (strcmp(sym, rel_to_symname(rel)) == 0)
return true;
}
return false;
}
template<typename Rel>
inline char *rel_to_symname(const Rel *rel) const
{
return dynstr + dynsym[rel->getSymbol()].st_name;
}
};
BOOL is_module_sanitized(void *handle)
{
plt_sym_resolver psr;
if (!psr.init(handle))
return FALSE;
return psr.is_symbol_available("__asan_init") ? TRUE : FALSE;
}
|